当前位置: 代码迷 >> Android >> 屏幕旋转时的Android Kotlin Coroutine
  详细解决方案

屏幕旋转时的Android Kotlin Coroutine

热度:166   发布时间:2023-08-04 12:37:49.0

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

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

现在,在屏幕旋转时,我希望UI保持使用正确的计数器值进行更新。 是否有人对如何在更改配置(例如屏幕旋转)时恢复作业有任何想法。

默认情况下,轮播会杀死活动并重新启动它。 这意味着您的textview将不再是屏幕上的那个,而是属于旧活动的那个。

您的选择是:

1)向您的清单添加configSettings以关闭此行为。

2)使用可以在活动重启后持续存在的内容,例如视图模型,加载程序,注入的事件总线等。

就个人而言,除非纵向和横向的布局不同,否则我只会使用数字1,它会更容易。

您可以在ViewModel中而不是Activity中进行操作。

是否有人对如何在更改配置(例如屏幕旋转)时恢复作业有任何想法。

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

从技术上讲,您可以将应用程序配置为不在轮播中重新创建活动,但Google强烈建议您不要这样做。 该应用程序似乎可以轮换使用,但随后会中断另一种配置更改,如时区,位置等。您只需轻咬一下,并使您的应用程序在活动娱乐活动中正常工作。

我通过设置Fragment使我的协程在整个活动娱乐中发挥作用

retainInstance = true

这意味着您的片段实例可以幸免于其父活动的死亡,并且当新活动替换它时,Android会将片段插入其中,而不是创建一个新的活动。 不能防止破坏视图层次结构,您必须编写代码来更新片段的状态以反映这些更改。 它之所以有用,是因为它使您可以保留片段的状态,而不必为打包而烦恼。

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

  1. onDestroyView
  2. onCreateView

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

kotlinx.coroutines的最新发布的0.23版本kotlinx.coroutineslaunch成为了扩展功能:您必须在一些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的不方便时刻发生计时器滴答声,协程将仅默默地跳过更新视图,并在下一个滴答声再试一次。

  相关解决方案