Android使用flowWithLifecycle监听Flow时context空指针问题解决方案
场景
需要加载大量数据后基于这些数据创建UI元素,该操作仅用于测试,问题就出在该环节。
问题
如果使用flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.STARTED),会出现在Fragment不再活跃时(如屏幕旋转、主题切换等场景后)仍收到数据回调的情况,进而触发context空异常。原实现方案不存在该问题。
当前可行方案
以下是运行正常的实现代码:
class MyFragment : Fragment { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 基于Flow更新UI lifecycleScope.launch(Dispatchers.IO) { DataManager .flowExercises() .take(1) .collect { // 为保证安全,此处检查当前生命周期状态! if (lifecycle.currentState >= Lifecycle.State.STARTED) { val views = it.map { TextView(context).apply { text = it.exercise.name gravity = Gravity.CENTER_HORIZONTAL } } withContext(Dispatchers.Main) { views.forEach { ll.addView(it) } } } } } } }
不生效的新方案
希望切换到flowWithLifecycle的实现方式,但无法保证运行稳定性,以下是尝试代码:
class MyFragment : Fragment { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 基于Flow更新UI lifecycleScope.launch(Dispatchers.IO) { DataManager .flowExercises() .take(1) .flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.STARTED) // 映射操作可能耗时较长... .map { it.map { TextView(context).apply { text = it.exercise.name gravity = Gravity.CENTER_HORIZONTAL } } } .collect { withContext(Dispatchers.Main) { views.forEach { ll.addView(it) } } } } } }
最终可行方案
DataManager .flowExercises() // 该操作为IO操作,耗时较长 .map { // 该操作同样耗时,此处仅为测试创建大量视图 // 每次都检查context,因为该阶段Fragment可能已销毁 it.map { data -> // 如果context不可用,说明Fragment已未挂载 // => 无需继续创建视图,结果最终也会被丢弃 // => 是的,这部分工作可能属于无效操作... context?.let { TextView(it).apply { text = data.exercise.name gravity = Gravity.CENTER_HORIZONTAL } } } } .flowOn(Dispatchers.IO) // 上述代码运行在IO线程 .flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.STARTED) .onEach { views -> // 当前处于STARTED状态,可安全操作UI views.forEach { ll.addView(it) } } .flowOn(Dispatchers.Main) // 上述代码运行在主线程 .launchIn(viewLifecycleOwner.lifecycleScope)
内容的提问来源于stack exchange,提问作者prom85
相关产品推荐
相关产品推荐

