在不使用ViewModel的情况下通过配置更改保留CoroutineScope的干净方法 [英] Clean way to retain CoroutineScope through config changes without ViewModel

查看:315
本文介绍了在不使用ViewModel的情况下通过配置更改保留CoroutineScope的干净方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道推荐将ViewModel与我们的Activity一起使用,因此我们可以使用其viewModelScope.由于ViewModel超过了Activity的寿命,因此我们不必取消activity.onDestroy()中的作业.

I know the recommendation is to use a ViewModel with our Activity, so we can use its viewModelScope. Since the ViewModel outlives the Activity, we don't have to cancel our jobs in activity.onDestroy().

但是,有时您的活动很简单.例如,它可以使用已安装的已过滤软件包填充列表视图.您可以非常简单地使用委托为活动创建范围,并在onDestroy()中取消作业:

However, sometimes you have a dirt-simple Activity. For example, it could populate a list view with filtered packages that are installed. You can very simply create a scope for the activity using a delegate, and cancel jobs in 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)
                     )
                 }
        }

}

在这种情况下,ViewModel感觉有些过分.这将是抽象PackageManager的另一层,它实际上是一个视图模型.

For a case like this, ViewModel feels like overkill. It would just be another layer to abstract the PackageManager, which is really a view model in itself.

上面的代码使在后台组装数据变得容易.问题在于,当旋转屏幕或进行其他配置更改时,协程将被取消并重新启动.对于这样的非常简单的活动,是否存在通过更改配置使CoroutineScope保持活动的干净方法?

The above code makes it easy to assemble the data in the background. The problem is that when the screen is rotated, or during other configuration changes, the coroutine is cancelled and restarted. Is there a clean recipe for keeping a CoroutineScope alive through a configuration change for a very simple Activity like this?

onRetainNonConfigurationInstance()已过时.我想我们可以将其放在Fragment中并使用retainInstance = true,但是在如此简单的Activity中引入Fragment层也感觉像是过分杀伤了.

onRetainNonConfigurationInstance() is deprecated. I suppose we could put it in a Fragment and use retainInstance = true, but introducing a Fragment layer to such a simple Activity also feels like overkill.

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

Maybe there's a way to create an empty ViewModel implementation just so we can borrow its scope?

推荐答案

在这种情况下,ViewModel感觉有些过分.

For a case like this, ViewModel feels like overkill.

我会反驳,但仍然建议这将是 .

I would argue otherwise and still suggest this would be a good use case for AndroidViewModel.

我相信,仅由于Activity有权访问PackageManager并不是获取包列表的责任. Activity应该只负责显示列表.

I believe that it is not the Activity's responsibility to fetch the package list just because it has access to the PackageManager. The Activity should only be responsible for displaying the list.

使用AndroidViewModel可以访问ViewModel实例中的ContextviewModelScope.

Using AndroidViewModel gives you access to Context and viewModelScope within your ViewModel instance.

这篇关于在不使用ViewModel的情况下通过配置更改保留CoroutineScope的干净方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆