在没有 ViewModel 的情况下通过配置更改保留 CoroutineScope 的干净方法

Ten*_*r04 5 android kotlin kotlin-coroutines

我知道建议将 ViewModel 与我们的 Activity 一起使用,因此我们可以使用它的viewModelScope. 由于 ViewModel 比活动寿命更长,我们不必取消activity.onDestroy().

但是,有时您会遇到非常简单的 Activity。例如,它可以使用已安装的过滤包填充列表视图。您可以非常简单地使用委托为活动创建一个范围,并在onDestroy()以下位置取消作业:

class MyActivity(): AppCompatActivity(), CoroutineScope by MainScope() {

    private val listAdapter = MyAdapter()

    override fun onCreate() {
        super.onCreate()
        setContentView(R.layout.my_activity)
        recycler_view.apply {
            layoutManager = LinearLayoutManager(this)
            adapter = listAdapter
        }
        launch {
            val packages = getOrgPackagesWithIcons()
            adapter.apply {
                data = packages
                notifyDataSetChanged()
            }
        }

    }

    override fun onDestroy() {
        super.onDestroy()
        cancel() // CoroutineContext
    }

    private suspend fun getOrgPackagesWithIcons() = withContext(Dispatchers.Default) {
        var toNextYield = 20
        packageManager.getInstalledPackages(0)
            .filter { it.packageName.startsWith("org")
            .take(100)
            .map { 
                     if (--toNextYield == 0) { // Make it cancellable
                         toNextYield = 20
                         yield()
                     }
                     MyPackageData(
                         it.applicationInfo.loadLabel(packageManager).toString(),
                         it.packageName,
                         it.applicationInfo.loadIcon(packageManager)
                     )
                 }
        }

}
Run Code Online (Sandbox Code Playgroud)

对于这种情况,ViewModel 感觉有点矫枉过正。它只是抽象 PackageManager 的另一层,它本身就是一个视图模型。

上面的代码可以很容易地在后台组装数据。问题是当屏幕旋转时,或者在其他配置更改期间,协程被取消并重新启动。对于像这样的非常简单的活动,是否有通过配置更改来保持 CoroutineScope 活动的干净方法?

onRetainNonConfigurationInstance()已弃用。我想我们可以把它放在一个 Fragment 中并使用retainInstance = true,但是为这样一个简单的 Activity 引入一个 Fragment 层也感觉有点矫枉过正。

也许有一种方法可以创建一个空的 ViewModel 实现,以便我们可以借用它的范围?

Emm*_*uel 4

对于这样的情况,ViewModel 感觉有点大材小用。

我会反对,但仍然建议这将是一个很好的用例AndroidViewModel

我相信仅仅Activity因为它可以访问PackageManager. 应该Activity只负责显示列表。

使用AndroidViewModel使您可以访问实例Context并在实例viewModelScope内进行访问ViewModel

  • 我的问题发生了变化,因为我认为您已经让我相信,即使在如此简单的示例中,在像 Activity 这样的 UI 类中进行数据采集也是糟糕的设计。重新熟悉 ViewModel,我发现它已经按照我想要的方式运行,在拥有活动完成时自动取消作业(但在配置更改时不会)。如果您的数据需要比特定 Activity 的生命周期更长,您可以创建一个存储库单例类,该类使用 Application 引用检索其实例,并且您可以使用 AndroidViewModel 的“application”实例来检索它。 (2认同)