【问题标题】:Fragment and viewLifecycleOwner deviationFragment与视图LifecycleOwner的偏差
【发布时间】:2020-11-05 19:45:53
【问题描述】:

我正在viewLifecycleOwner 上收集流量。它在Dispatchers.Default 上流动,但收集本身在Dispatchers.Main 上进行。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    viewLifecycleOwner.lifecycleScope.launch {
        flow.flowOn(Default).collect {
            requireContext()
        }
    }
}

在一次情况下,我发现IllegalStateException 声明该片段未附加。

IllegalStateException:片段测试未附加到上下文。

我假设在分离片段之前会取消流的收集。

协程如何在分离的片段上恢复?

【问题讨论】:

  • 我对@9​​87654326@不熟悉。由于lifecycleScope 是协程作用域,它会在组件销毁时被销毁。我们可以在内部范围集合中检查if(parentScope.isActive) 吗?
  • @ADM 我还不知道复制。我会为将来添加更多日志记录,但我不知道它什么时候会再次发生......
  • 据我了解,IllegalStateException 表示即使生命周期范围被破坏,内部范围仍会继续执行,这就是我建议 if(parentScope.isActive) 的原因。我们不能简单地将Dispatcher 传递给viewLifecycleOwner.lifecycleScope.launch 或者Dispatcher,IO 并以这种方式直接收集流量,这样只会有一个范围。这适用于 Flow 吗?
  • @ADM 收集需要在Main 上恢复。流本身是一个依赖项,之前也设置了flowOnIllegalStateException 表示生命周期在onDetach 之后。是否有可能在片段被销毁之前调度了收集器,因此 Runnable 在Main 上排队?我认为isActive 可能是需要观察的重要信息。遗憾的是,我刚刚收到通知,用户没有观察到崩溃。所以可能与应用更新或进程关闭有关。

标签: android kotlin android-fragments kotlin-coroutines kotlin-flow


【解决方案1】:

首先,值得注意的是flowOn改变了上游上下文,以防你在@987654325之前有mapfilter等运算符函数@。因此,它不会影响collect 等终端函数的上下文。在kotlin docs 上有说明。所以,如果你想改变collect 终端的上下文,你应该从外部块改变它,我的意思是launch builder 函数。

接下来,为了避免IllegalStateException 以安全的方式使用context,而不是requireContext(),以确保附加了片段。毫无疑问,当片段被销毁时,viewLifecycleOwner.lifecycleScope 中启动的所有协程都应该终止,但在某些情况下,线程中可能存在导致此问题的竞争条件。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    viewLifecycleOwner.lifecycleScope.launch(Main/Default/WhateverContextYouWant) {
        flow.collect {
            context?.let { }
        }
    }
}

【讨论】:

  • 遗憾的是,这不是一个选项。流需要在Default 上流动,而收集需要在Main 上暂停。 requireContext() 本身是间接调用的。我可以检查 Fragment 是否仍然附加,但我更愿意相信取消集合的范围,或者至少了解为什么在应该取消的情况下恢复了某些内容。
  • kotlin 中的冷流支持背压,因此提供值完全独立于收集。因此,您在流上提供值的上下文不会影响集合。您可以在IODefault 上下文上发出值,但在Main 上收集它们。因此,如果您希望值在 Default 上传输,您应该在定义流的位置(并发出值)而不是集合的位置执行此操作。
  • 理论上,我们必须依赖我们被告知的内容,我的意思是当一个范围被取消时,所有正在运行的协程也将被取消。但问题是,我认为在时间上可能会有罕见的例外。
猜你喜欢
  • 2021-11-18
  • 1970-01-01
  • 2020-03-03
  • 1970-01-01
  • 1970-01-01
  • 2015-09-23
  • 1970-01-01
  • 2014-04-27
  • 1970-01-01
相关资源
最近更新 更多