需求描述
广告引导页需求描述:
- 用户打开App显示5秒钟的广告,广告结束后进入App主页面。
- 广告结束前,用户可以点击跳过广告。
- 页面销毁时,计时器销毁。
代码示例
AdvertisingManage1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
|
class AdvertisingManage { val TAG = "TAG_AdvertisingManage" var advertisingManageListener : AdvertisingManageListener ?=null
private var countDownTimer:CountDownTimer?=object : CountDownTimer(5000,1000){ override fun onTick(millisUntilFinished: Long) { Log.d(TAG,"广告剩余时间${(millisUntilFinished/1000).toInt()}秒") advertisingManageListener?.timing((millisUntilFinished/1000).toInt()) }
override fun onFinish() { Log.d(TAG,"广告结束,准备进入主界面") advertisingManageListener?.enterMainActivity() } }
fun start(){ Log.d(TAG,"开始计时") countDownTimer?.start() }
fun onCancel(){ Log.d(TAG,"停止计时") countDownTimer?.cancel() countDownTimer = null }
interface AdvertisingManageListener{
fun timing(second:Int)
fun enterMainActivity() } }
|
AdvertisingActivity1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
class AdvertisingActivity : BaseActivity() { lateinit var btnIngore:Button lateinit var tvAdvertisingTime:TextView
private var advertisingManage:AdvertisingManage?=null
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_advertising) btnIngore = findViewById(R.id.btn_ignore) as Button tvAdvertisingTime = findViewById(R.id.tv_advertising_time) as TextView
advertisingManage = AdvertisingManage() advertisingManage?.advertisingManageListener = object : AdvertisingManage.AdvertisingManageListener{ override fun timing(second: Int) { tvAdvertisingTime.text = "广告剩余$second 秒" }
override fun enterMainActivity() { MainActivity.actionStart(this@AdvertisingActivity) finish()
} } btnIngore.setOnClickListener{ MainActivity.actionStart(this) finish()
} advertisingManage?.start() }
override fun onDestroy() { super.onDestroy() advertisingManage?.onCancel() } }
|
activity_advertising1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto">
<Button android:id="@+id/btn_ignore" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="跳过广告页"/>
<TextView android:id="@+id/tv_advertising_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" android:layout_marginEnd="10dp" android:layout_marginTop="10dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
|
AndroidManifest.xml1 2 3 4 5 6 7 8 9 10 11 12
| <application ... <activity android:name=".ui.advertising.AdvertisingActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".ui.MainActivity"/> ... </application>
|
使用Lifecycle优化上面代码:使业务功能与Activity业务逻辑分离
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| class AdvertisingManage:LifecycleObserver{ val TAG = "TAG_AdvertisingManage"
var advertisingManageListener : AdvertisingManageListener ?=null
private var countDownTimer:CountDownTimer?=object : CountDownTimer(5000,1000){ override fun onTick(millisUntilFinished: Long) { Log.d(TAG,"广告剩余时间${(millisUntilFinished/1000).toInt()}秒") advertisingManageListener?.timing((millisUntilFinished/1000).toInt()) }
override fun onFinish() { Log.d(TAG,"广告结束,准备进入主界面") advertisingManageListener?.enterMainActivity() } }
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE) fun start(){ Log.d(TAG,"开始计时") countDownTimer?.start() }
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun onCancel(){ Log.d(TAG,"停止计时") countDownTimer?.cancel() countDownTimer = null }
interface AdvertisingManageListener{
fun timing(second:Int)
fun enterMainActivity() } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class AdvertisingActivity : BaseActivity() {
lateinit var btnIngore:Button lateinit var tvAdvertisingTime:TextView
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_advertising) btnIngore = findViewById(R.id.btn_ignore) as Button tvAdvertisingTime = findViewById(R.id.tv_advertising_time) as TextView
val advertisingManage = AdvertisingManage() lifecycle.addObserver(advertisingManage)
advertisingManage.advertisingManageListener = object : AdvertisingManage.AdvertisingManageListener{ override fun timing(second: Int) { tvAdvertisingTime.text = "广告剩余$second 秒" }
override fun enterMainActivity() { MainActivity.actionStart(this@AdvertisingActivity) finish() } } btnIngore.setOnClickListener{ MainActivity.actionStart(this) finish() } } }
|
解决横竖屏切换导致的计时重置
configChanges 属性
屏幕旋转时,横竖屏切换会导致重新执行每个生命周期方法,生命周期的变化取决于 configChanges 属性。
onSaveInstanceState 方法
通过重写 onSaveInstanceState 方法在 Activity 被销毁时将计时的节点存储起来
1 2 3 4 5 6 7 8 9 10 11
| class AdvertisingManage(millisInFuture:Long=5000):LifecycleObserver{ ...
private var countDownTimer:CountDownTimer?=object : CountDownTimer(millisInFuture,1000){ ... }
... }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class AdvertisingActivity : BaseActivity() { ... var millisInFuture:Long=5000 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_advertising)
... savedInstanceState?.let { millisInFuture = it.getLong(KEY_MILLISINFUTURE) } val advertisingManage = AdvertisingManage(millisInFuture) lifecycle.addObserver(advertisingManage)
advertisingManage.advertisingManageListener = object : AdvertisingManage.AdvertisingManageListener{ override fun timing(second: Int) { tvAdvertisingTime.text = "广告剩余$second 秒" millisInFuture = second.toLong() * 1000 }
... } ... }
override fun onSaveInstanceState(outState: Bundle, outPersistentState: PersistableBundle) { super.onSaveInstanceState(outState, outPersistentState) outState.putLong(KEY_MILLISINFUTURE,millisInFuture) } companion object{ const val KEY_MILLISINFUTURE = "keyMillsinfuture" } }
|
使用 ViewModel
1 2 3 4 5 6 7
|
class AdvertisingViewModel(application: Application) : AndroidViewModel(application) {
var millisInFuture:Long=5000 }
|
1 2 3 4 5 6 7 8
| class AdvertisingManage(millisInFuture:Long=5000):LifecycleObserver{ ... private var countDownTimer:CountDownTimer?=object : CountDownTimer(millisInFuture,1000){ ... } ... }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| class AdvertisingActivity : BaseActivity() { private val TAG = "TAG_AdvertisingActivity" lateinit var btnIngore:Button lateinit var tvAdvertisingTime:TextView
private lateinit var advertisingViewModel: AdvertisingViewModel
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_advertising)
initView() initData() }
private fun initData() { advertisingViewModel = ViewModelProvider(this).get(AdvertisingViewModel::class.java)
val advertisingManage = AdvertisingManage(advertisingViewModel.millisInFuture) lifecycle.addObserver(advertisingManage)
advertisingManage.advertisingManageListener = object : AdvertisingManage.AdvertisingManageListener{ override fun timing(second: Int) { tvAdvertisingTime.text = "广告剩余$second 秒" advertisingViewModel.millisInFuture = second.toLong() * 1000 }
override fun enterMainActivity() { MainActivity.actionStart(this@AdvertisingActivity) finish() } } }
private fun initView() { btnIngore = findViewById(R.id.btn_ignore) as Button tvAdvertisingTime = findViewById(R.id.tv_advertising_time) as TextView
btnIngore.setOnClickListener{ MainActivity.actionStart(this) finish() } } }
|
使用 LiveData
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class AdvertisingViewModel(application: Application) : AndroidViewModel(application) {
var millisInFuture:Long=5000
private var timingResult = MutableLiveData<Long>()
val _timingResult:LiveData<Long> get() = timingResult
fun setTimingResult(millisInFuture: Long){ timingResult.value = millisInFuture } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class AdvertisingManage(advertisingViewModel: AdvertisingViewModel):LifecycleObserver{ val TAG = "TAG_AdvertisingManage"
private var countDownTimer:CountDownTimer?=object : CountDownTimer(advertisingViewModel.millisInFuture,1000){ override fun onTick(millisUntilFinished: Long) { Log.d(TAG,"广告剩余时间${(millisUntilFinished/1000).toInt()}秒") advertisingViewModel.setTimingResult(millisUntilFinished/1000) }
override fun onFinish() { Log.d(TAG,"广告结束,准备进入主界面") } }
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE) fun start(){ Log.d(TAG,"开始计时") countDownTimer?.start() }
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun onCancel(){ Log.d(TAG,"停止计时") countDownTimer?.cancel() countDownTimer = null } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| class AdvertisingActivity : BaseActivity() { private val TAG = "TAG_AdvertisingActivity" lateinit var btnIngore:Button lateinit var tvAdvertisingTime:TextView
private lateinit var advertisingViewModel: AdvertisingViewModel
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_advertising)
initView() initData() }
private fun initData() { advertisingViewModel = ViewModelProvider(this).get(AdvertisingViewModel::class.java)
val advertisingManage = AdvertisingManage(advertisingViewModel) lifecycle.addObserver(advertisingManage)
advertisingViewModel._timingResult.observe(this, Observer { tvAdvertisingTime.text = "广告剩余$it 秒" if (it == 0L){ Log.d(TAG,"广告结束,准备进入主页面") MainActivity.actionStart(this@AdvertisingActivity) finish() } })
}
private fun initView() { btnIngore = findViewById(R.id.btn_ignore) as Button tvAdvertisingTime = findViewById(R.id.tv_advertising_time) as TextView
btnIngore.setOnClickListener{ MainActivity.actionStart(this) finish() } } }
|
备注
参考资料:
《Android Jetpack开发 原理解析与应用实战》
欢迎关注微信公众号:非也缘也