1. 坑人的 Handler
大家都知道 Handler 特别坑,使用不当会造成各种问题:
Activity
中使用 Handler 有可能会造成Context
内存泄漏;Handler()
默认构造函数会因为缺少Looper
而崩溃(虽然已标位 deprecated ) ;View.post/postDelayed
基于 Handler 实现,在View
已经 detached 时可能仍在执行,造成异常
诸如上述这些问题让开发者们防不胜防,但是 Handler 便利性又让开发者们难以割舍。大家希望寻找一种同样方便但更安全的替代方案。如今借助 Kotlin Coroutine + Lifecycle 我们可以做到这一切,思路很简单:利用协程执行异步任务,同时绑定 Lifecycle ,在必要的时候终止任务
2. 替代 Handler.post/postDelayed
项目中添加 coroutie 和 lifecycle 依赖:
implementation "andoridx.lifecycle:lifecycle-runtime-ktx:2.3.1" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3"
代码如下
fun LifecycleOwner.postDelayedOnLifecycle( duration: Long, dispatcher: CoroutineDispatcher = Dispatchers.Main, block: () -> Unit ): Job = lifecycleScope.launch(dispatcher) { delay(duration) block() }
因为 Handler.post
运行在 UI 线程, 所以 Dispatcher 默认使用 Dispatchers.Main
,postDelayed
的延时使用 delay
实现。
使用效果如下,在 Activity 或 Fragment 中无需再依赖 Handler 了
class MainActivity : AppCompatActivity() { ... postDelayedOnLifecycle(500L) { //Do something } ... }
3. 替代 View.post/postDelayed
我们还可以借助 lifecycle-ktx 提供的 View 的扩展方法 findViewTreeLifecycleOwner(),替代 View.post / View.postDelayed , findViewTreeLifecycleOwner 可以从当前 View 最近的 Fragment 或者 Activity 获取 LifecycleOwner。
代码如下:
fun View.postDelayedOnLifecycle( duration: Long, dispatcher: CoroutineDispatcher = Dispatchers.Main, block:() -> Unit ) : Job? = findViewTreeLifecycleOwner()?.let { lifecycleOwner -> lifecycleOwner.lifecycleScope.launch(dispatcher) { delay(duration) block() } }