Android Kotlin协同程序屏幕旋转

Android Kotlin协同程序屏幕旋转,android,kotlin,kotlinx.coroutines,Android,Kotlin,Kotlinx.coroutines,我正在启动一个协同程序,在指定的延迟后在屏幕上显示一个计数器值 job = launch(UI) { var count= 0 while (true) { textView.text = "${count++}" delay(200L) } } 现在,在屏幕旋转中,我希望用户界面不断得到正确计数器值的更新。是否有人知道如何在配置(如屏幕旋转)更改时恢复作业 默认情况下,旋转会终止活动并重新启动它。这意味着您的文本视图将不再

我正在启动一个协同程序,在指定的延迟后在屏幕上显示一个计数器值

job = launch(UI) {
    var count= 0
      while (true) {
        textView.text = "${count++}"
        delay(200L)
      }
   }

现在,在屏幕旋转中,我希望用户界面不断得到正确计数器值的更新。是否有人知道如何在配置(如屏幕旋转)更改时恢复作业

默认情况下,旋转会终止活动并重新启动它。这意味着您的文本视图将不再是屏幕上的文本视图,而是属于旧活动的文本视图

你的选择是:

1) 将configSettings添加到清单以关闭此行为

2) 在活动重新启动时使用一些可以持久化的东西,如视图模型、加载程序、注入的事件总线等


就我个人而言,除非你有不同的纵向和横向布局,否则我只选择1号布局,它更容易。

你可以在ViewModel中完成,而不是在Activity中

是否有人知道如何在配置(如屏幕旋转)更改时恢复作业

您的作业从未停止运行,但您一直保持并更新一个不再显示在屏幕上的
TextView
。配置更改后,您的活动及其整个视图层次结构将被删除

虽然从技术上讲,你可以配置你的应用程序,使其不在轮换时重新创建活动,但谷歌强烈反对你这样做。该应用程序似乎在轮换的情况下工作,但随后将在另一种配置更改(如时区、位置等)上中断。你只需咬紧牙关,让你的应用程序在活动娱乐活动中工作

我通过依赖我设置的a
片段,使我的协同程序在活动娱乐中工作

retainInstance = true
这意味着您的片段实例在其父活动死亡后仍能生存,并且当新活动替换它时,Android会将您的片段注入其中,而不是创建一个新的片段。它不能阻止视图层次结构的破坏,您必须编写更新片段状态的代码来反映这些更改。它很有帮助,因为它允许您保持片段的状态,而不必费心进行打包

在配置更改时,您的片段将经历以下生命周期事件:

  • onDestroyView
  • onCreateView
  • 它不会在暂停时执行
    onPause
    /
    onResume
    ,只有在您切换活动或退出应用程序时才会执行此操作。您可以在
    onResume
    中启动协作程序,并在
    onPause
    中取消协作程序

    从最近发布的
    kotlinx.coroutines
    的0.23版开始,
    launch
    成为一个扩展函数:您必须在控制生成作业生命周期的某些
    CoroutineScope
    的上下文中调用它。您应该将其生命周期绑定到片段,因此让片段实现
    CoroutineScope
    。另一个变化是,
    UI
    coroutine上下文现在被弃用,取而代之的是
    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时,计时器滴答声恰好出现在不方便的时刻,则协同程序将自动跳过更新视图,并在下一滴答声时重试。

    我想我回答问题的方式是错误的。基本上,我的问题更多地与kotlin coroutine的工作重启有关。我可以存储作业本身并恢复它吗?您仍然需要一个存储作业的位置。