是否有人知道如何在配置(例如屏幕旋转)更改时恢复工作。
您的工作从未停止运行,但您一直坚持并更新不再显示在屏幕上的TextView。配置更改后,您的 Activity 及其整个视图层次结构被抓取。
虽然从技术上讲,您可以将应用配置为不重新创建轮换活动,但 Google 强烈建议您不要这样做。该应用似乎适用于轮换情况,但随后会因另一种配置更改(如时区、位置等)而中断。您只需要硬着头皮让您的应用在活动娱乐事件中正常工作。
我通过我设置的 Fragment 使我的协程在活动娱乐中工作
retainInstance = true
这意味着您的片段实例在其父 Activity 死亡后仍然存在,并且当新 Activity 替换它时,Android 会将您的片段注入其中而不是创建一个新片段。它确实不阻止视图层次结构的破坏,您必须编写更新片段状态的代码以反映这些更改。这很有帮助,因为它允许您保持片段的状态,而不是为包裹化而烦恼。
在配置更改时,您的片段将经历这些生命周期事件:
onDestroyView
onCreateView
它不会通过onPause/onResume,这只会在您切换活动或退出应用程序时发生。您可以在onResume 中启动您的协程并在onPause 中取消它。
从最近发布的kotlinx.coroutines 0.23 版开始,launch 成为一个扩展函数:您必须在控制生成作业生命周期的某些CoroutineScope 的上下文中调用它。您应该将其生命周期绑定到片段,因此让您的片段实现CoroutineScope。另一个变化是 UI 协程上下文现在已弃用,取而代之的是 Dispatchers.Main。
这是一个简短的例子,展示了我提到的所有要点:
class MyFragment : Fragment, CoroutineScope {
private var textView: TextView? = null
private var rootJob = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + rootJob
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
val rootView = inflater.inflate(R.layout.frag_id, container, false)
this.textView = rootView.findViewById(R.id.textview)
return rootView
}
override fun onDestroyView() {
this.textView = null
}
override fun onResume() {
this.launch {
var count = 0
while (true) {
textView?.text = "$count"
count++
delay(200L)
}
}
}
override fun onPause() {
rootJob.cancel()
rootJob = Job()
}
}
现在,随着视图层次结构的重建,您的协程将自动获取 textView 的当前实例。如果在重建 UI 的过程中发生了不方便的计时器滴答,协程将静默跳过更新视图并在下一个滴答时重试。