在Android开发中,我们经常使用Handler去实现一些延时任务,非常的方便,但是如果使用不当,或者说考虑不够周全就会引起一些bug甚至是崩溃。
首先我们看看使用Handler在View中实现延时任务:
class MyView constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
init {
postDelayed({
//...
}, 300)
}
}
当我们调用handler.postDelayed(runnable)
时,会将此runnable封装成一个Message添加到MessageQueue中,最后在主线程中执行,但是这样就有可能会出现,当执行Runnable的时候,该View已经detached或者Activity销毁了,这样的话就可能会出现一些异常情况甚至引起崩溃。
下面看看如何使用Kotlin Coroutine和LifeCycle的方式来实现延时任务,首先在build.gradle中引入协程和lifecycle相关的依赖:
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0'
为了要确保延时任务执行时,View和Activity还处于活跃状态,我们需要能够感应到Activity的生命周期,lifecycle库中为我们提供了一个扩展方法findViewTreeLifecycleOwner
来获取View所属的lifecycleOwner,下面就可以为View再添加一个扩展方法实现延时任务。
fun View.delayOnLifecycle(
durationInMills: Long,
dispatcher: CoroutineDispatcher = Dispatchers.Main,
block: () -> Unit
): Job? = findViewTreeLifecycleOwner()?.let {
it.lifecycle.coroutineScope.launch(dispatcher) {
delay(durationInMills)
block()
}
}
当我们需要使用view来实现延时任务,就可以调用
view.delayOnLifecycle(300) {
//...
}
这样执行的延时任务就感应Activity的生命周期,在Activity销毁后就会取消延迟任务,不会引起异常情况。