【问题标题】:Update UI in coroutine after Activity.onDestroy()在 Activity.onDestroy() 之后更新协程中的 UI
【发布时间】:2019-02-04 09:40:43
【问题描述】:

我的活动中有此代码:

private val job = Job()
private val ioScope = CoroutineScope(Dispatchers.IO + job)
private val uiScope = CoroutineScope(Dispatchers.Main + job)

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_second)

    ioScope.launch {
        delay(3000L)
        textView.text = "test1"
        uiScope.launch {
            textView.text = "test2"
        }
    }
}

如果我启动并等待 3 秒,应用程序将崩溃并显示 CalledFromWrongThreadException,这是可以预见的,因为我从 textView.text = "test1" 行中的后台线程更新 Ui。

但是如果我按下后退按钮,我会看到 onPause() 和 onDestroy() 将被调用,但后台线程中的 textView.text = "test1" 和 UI 线程中的 textView.text = "test1" 都会被调用,但无一例外。

为什么它没有崩溃,因为我更新了销毁活动的 UI?

这样写代码安全吗?例如,响应后进行网络调用和更新 UI(当 Activity 可能被销毁时),或者可能会出现一些问题?

【问题讨论】:

  • 通常,当Activity被销毁时,我们会在onDestroy()方法中调用uiScope.cancel()来停止协程的工作。
  • @Sergey 是的,我看到了,但是如果不打电话会怎样?
  • 我猜协程会继续工作的。

标签: android kotlin kotlinx.coroutines


【解决方案1】:

您基本上是通过不取消协程而导致(临时)内存泄漏。 Activity 销毁后更新 View 实际上不会引发任何异常;相反,这些更改不会反映在任何 UI 中。您正在更新已被丢弃的 Activity 中的值,但由于您的协程保留对它的引用,因此仅保留在内存中。

正如@Sergey 提到的,您应该在onDestroy()job.cancel()

【讨论】:

  • 我理解对吗:这样写代码不会出现问题,协程结束后Activity会被释放?所以,一般来说,在不取消 onDestroy 的情况下,为互联网/数据库请求等短期操作启动协程是可以接受的?
  • 不行,你肯定要在activity销毁后清理。如果不仅仅是为了内存影响,您可以在 Activity 被销毁后在它中执行一些操作,这些操作导致崩溃,并且这些问题将难以重现。
  • “在Activity被销毁后更新View实际上不会引发任何异常”引用死视图时KotlinNullPointerException怎么样?
  • 除非您明确将其设置为 null,否则它不会为 null。如果它可以为空,那么无论如何您都必须使用不安全的view!! 来导致 NPE。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-06
  • 2013-09-14
  • 2021-03-06
  • 1970-01-01
  • 1970-01-01
  • 2019-07-07
  • 2010-09-14
相关资源
最近更新 更多