Android Kotlin Coroutine 屏幕旋转

标签 android kotlin kotlinx.coroutines

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

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

现在在屏幕旋转时,我希望 UI 不断更新正确的计数器值。有人知道如何在配置(例如屏幕旋转)更改时恢复工作吗?

最佳答案

Does someone has any idea how to resume the job on configuration(e.g. screen rotation) change.

您的工作从未停止运行,但您一直坚持并更新 TextView不再显示在屏幕上。配置更改后,您的 Activity 及其整个 View 层次结构都被抓取了。

虽然从技术上讲,您可以将您的应用配置为不重新创建旋转 Activity ,但 Google 强烈建议您不要这样做。该应用程序似乎适用于旋转的情况,但随后会中断另一种配置更改,如时区、位置等。您只需要咬紧牙关,让您的应用程序在 Activity 娱乐事件中工作。

我依靠一个 Fragment 让我的协程跨 Activity 娱乐工作我在其中设置

retainInstance = true

这意味着您的 fragment 实例在其父 Activity 终止后仍然存在,并且当新 Activity 取代它时,Android 会将您的 fragment 注入(inject)其中而不是创建一个新的。它不会阻止 View 层次结构的破坏,您必须编写更新 fragment 状态的代码以反射(reflect)这些变化。它有帮助,因为它允许您保持 fragment 的状态,而不是为分割而烦恼。

在配置更改时,您的 fragment 将经历这些生命周期事件:

  1. onDestroyView
  2. onCreateView

它不会通过 onPause/onResume ,这只会在您切换 Activity 或退出应用程序时发生。您可以在 onResume 中启动协程并在onPause中取消.

截至最近发布的 0.23 版 kotlinx.coroutines , launch成为一个扩展函数:你必须在一些 CoroutineScope 的上下文中调用它它控制生成的作业的生命周期。你应该将它的生命周期绑定(bind)到 fragment ,所以让你的 fragment 实现 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()
    }
}

现在,随着 View 层次结构的重建,您的协程将自动获取 textView 的当前实例。 .如果在重建 UI 时一个不方便的时刻恰好发生计时器滴答,协程将静默地跳过更新 View 并在下一个滴答时重试。

关于Android Kotlin Coroutine 屏幕旋转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52348349/

相关文章:

java - 通过过滤显示或隐藏 HashMap 标记

android - RushORM 存储 RequestParams

android - 用户滚动到 ScrollView Android 底部后启用按钮

Java/Kotlin : Return object from function vs not returning it

kotlin - 如何使用 Kotlin 协程从 Deferred future 创建 Observable

如果最后一个操作异常完成,Kotlin 协程会立即给出异常

java - RegEx - 匹配 java 中的整个 <a> 标签

Android adb shell - ash 还是 ksh?

kotlin - Kotlin 挂起函数处于等待状态和处于挂起状态之间有区别吗?

gradle - `runBlocking` coroutine builder is not resolved in the project(其他builder已解析)