使用协程替换Handler在View中实现延时任务

Android面试技术要点汇总
2021-05-17 14:29 · 阅读时长3分钟
小课

在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销毁后就会取消延迟任务,不会引起异常情况。

Viewkotlin coroutinehandlerandroid