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()
.
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)
)
}
}
}
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.
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()
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.
Maybe there's a way to create an empty ViewModel implementation just so we can borrow its scope?
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
.
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.
Using AndroidViewModel
gives you access to Context
and viewModelScope
within your ViewModel
instance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With