Android launchWhenXXX 和 repeatOnLifecycle"/>
Android launchWhenXXX 和 repeatOnLifecycle
文章目录
- Android launchWhenXXX 和 repeatOnLifecycle
- lifecycleScope和viewModelScope
- launchWhenXXX
- repeatOnLifecycle
- flowWithLifecycle
- 总结
Android launchWhenXXX 和 repeatOnLifecycle
lifecycleScope和viewModelScope
LiveData优点:
- 避免内存泄露风险:当 Activity/Fragment 进入 DESTROYED 时,会自动删除 Observer 。
- 节省资源:当 Activity/Fragment 进入活跃状态时才开始接受数据,避免 UI 处于后台时的无效计算。
Flow缺点:
Flow 基于协程实现,具有丰富的操作符,通过这些操作符可以实现线程切换、处理流式数据,相比 LiveData 功能更加强大。 但唯有一点不足,无法像 LiveData 那样感知生命周期。
lifecycleScope:
lifecycle-runtime-ktx
库提供了 lifecycleOwner.lifecycleScope
扩展,可以在当前 Activity 或 Fragment 销毁时结束此协程,防止泄露。
Flow 也是运行在协程中的,lifecycleScope
可以帮助 Flow 解决内存泄露的问题。
添加依赖库:
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.5.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.0"
class MyFragment: Fragment() {override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)viewLifecycleOwner.lifecycleScope.launch {val params = TextViewCompat.getTextMetricsParams(textView)val precomputedText = withContext(Dispatchers.Default) {PrecomputedTextCompat.create(longTextContent, params)}TextViewCompat.setPrecomputedText(textView, precomputedText)}}
}
class MyViewModel: ViewModel() {init {viewModelScope.launch {// Coroutine that will be canceled when the ViewModel is cleared.}}
}
launchWhenXXX
由于 lifecycleScope.launch 会立即启动协程,一直运行到协程销毁,不能监听生命周期。因此lifecycle-runtime-ktx
又为我们提供了 LaunchWhenStarted
和 LaunchWhenResumed
。
优点:
launchWhenXXX 会在 XXX 状态前一直等待,又在离开 XXX 状态后挂起协程,lifecycleScope+launchWhenXX的组合使用让 Flow 拥有了生命周期感知能力。
- 避免泄露:当 lifecycleOwner 进入 DESTROYED 时, lifecycleScope 结束协程
- 节省资源:当 lifecycleOwner 进入 STARTED/RESUMED 时 launchWhenX 恢复执行,否则挂起。
缺点:
对于 launchWhenXXX 来说, 当 lifecycleOwner 离开 XXX 状态时,协程只是挂起协程而非销毁,如果用这个协程来订阅 Flow,就意味着虽然 Flow 的收集暂停了,但是上游的处理仍在继续,资源浪费的问题解决地不够彻底。
class MyFragment: Fragment {init {lifecycleScope.launchWhenStarted {try {// Call some suspend functions.} finally {// This line might execute after Lifecycle is DESTROYED.if (lifecycle.state >= STARTED) {// Here, since we've checked, it is safe to run any// Fragment transactions.}}}}
}
repeatOnLifecycle
lifecycle-runtime-ktx 自 2.4.0-alpha01
起,提供了一个新的协程构造器 lifecyle.repeatOnLifecycle
, 它在离开 X 状态时销毁协程,再进入 X 状态时再启动协程。从其命名上也可以直观地认识这一点,即围绕某生命周期的进出反复启动新协程。
class MyFragment : Fragment() {val viewModel: MyViewModel by viewModel()override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)// Create a new coroutine in the lifecycleScopeviewLifecycleOwner.lifecycleScope.launch {// repeatOnLifecycle launches the block in a new coroutine every time the// lifecycle is in the STARTED state (or above) and cancels it when it's STOPPED.viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {// Trigger the flow and start listening for values.// This happens when lifecycle is STARTED and stops// collecting when the lifecycle is STOPPEDviewModel.someDataFlow.collect {// Process item}}}}
}
flowWithLifecycle
当我们只有一个 Flow 需要收集时,可以使用 flowWithLifecycle
这样一个 Flow 操作符的形式来简化代码。
viewLifecycleOwner.lifecycleScope.launch {exampleProvider.exampleFlow().flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.STARTED).collect {// Process the value.}
}
flowWithLifecycle源码:
本质仍然是对 repeatOnLifecycle 的封装。
public fun <T> Flow<T>.flowWithLifecycle(lifecycle: Lifecycle,minActiveState: Lifecycle.State = Lifecycle.State.STARTED
): Flow<T> = callbackFlow {lifecycle.repeatOnLifecycle(minActiveState) {this@flowWithLifecycle.collect {send(it)}}close()
}
总结
- lifecycleScope.launch:可以在当前 Activity 或 Fragment 销毁时结束此协程,防止泄露。
- launchWhenXXX:可以像 LiveData 那样感知生命周期,但是会挂起协程而非销毁,仍然存储资源浪费问题。
- repeatOnLifecycle:可以感知生命周期变化,进入指定状态后会销毁协程。
更多推荐
Android launchWhenXXX 和 repeatOnLifecycle
发布评论