问题描述
我正在启动协程,在指定的延迟后,协程将在屏幕上显示一个计数器值。
job = launch(UI) {
var count= 0
while (true) {
textView.text = "${count++}"
delay(200L)
}
}
现在,在屏幕旋转时,我希望UI保持使用正确的计数器值进行更新。 是否有人对如何在更改配置(例如屏幕旋转)时恢复作业有任何想法。
1楼
默认情况下,轮播会杀死活动并重新启动它。 这意味着您的textview将不再是屏幕上的那个,而是属于旧活动的那个。
您的选择是:
1)向您的清单添加configSettings以关闭此行为。
2)使用可以在活动重启后持续存在的内容,例如视图模型,加载程序,注入的事件总线等。
就个人而言,除非纵向和横向的布局不同,否则我只会使用数字1,它会更容易。
2楼
您可以在ViewModel中而不是Activity中进行操作。
3楼
是否有人对如何在更改配置(例如屏幕旋转)时恢复作业有任何想法。
您的工作从未停止过运行,但是您一直坚持并更新不再显示在屏幕上的TextView
。
更改配置后,您的活动及其整个视图层次结构都会被抓取。
从技术上讲,您可以将应用程序配置为不在轮播中重新创建活动,但Google强烈建议您不要这样做。 该应用程序似乎可以轮换使用,但随后会中断另一种配置更改,如时区,位置等。您只需轻咬一下,并使您的应用程序在活动娱乐活动中正常工作。
我通过设置Fragment
使我的协程在整个活动娱乐中发挥作用
retainInstance = true
这意味着您的片段实例可以幸免于其父活动的死亡,并且当新活动替换它时,Android会将片段插入其中,而不是创建一个新的活动。 它不能防止破坏视图层次结构,您必须编写代码来更新片段的状态以反映这些更改。 它之所以有用,是因为它使您可以保留片段的状态,而不必为打包而烦恼。
在更改配置时,您的片段将经历以下生命周期事件:
-
onDestroyView
-
onCreateView
它不会通过onPause
/ onResume
,只有在您切换活动或退出应用程序时才会发生。
您可以在onResume
启动协程,并在onPause
中将其取消。
从kotlinx.coroutines
的最新发布的0.23版本kotlinx.coroutines
, launch
成为了扩展功能:您必须在一些CoroutineScope
的上下文中调用它,该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的不方便时刻发生计时器滴答声,协程将仅默默地跳过更新视图,并在下一个滴答声再试一次。