Is it possible to provide once own implementation of a ViewModelStore
for ViewModelProviders
to use instead of the default one?
More precisely, I'm interested in adding fun clear(vm: ViewModel)
(or using an index or something similar) functionality to the ViewModelStore
so that I can clear a single view model of my choice, not just use the built in ViewModelStore#clear
:
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
which clears all view models.
A ViewModelStore can be considered as a container that stores the ViewModels in a HashMap . Where the key is string value and value is the ViewModel being saved( ViewModelProvider uses a concatenation of the string_key + ViewModel class canonical name). A ViewModelStoreOwner is merely an interface.
It is because of the Android system destroys the activity and recreates it from scratch, and as the activity is recreated, the old resources and instances of various classes(ViewModelProvider in our case) are first destroyed on calling onDestroy() method and later recreated in onCreate() .
ViewModel is a separate class which has an instance of it in the activity and has no reference for view in it. So even though activity onDestroy() and onCreate() happens on configuration change, the instance of ViewModel doesn't get destroyed or garbage collected.
Using ViewModel to Store UI State. The Android team introduced ViewModel and LiveData classes to help save state during configuration changes. A ViewModel stores and manages UI-related data in a lifecycle-conscious manner. Simply put, it allows data to survive configuration changes.
First, I think you should not consider doing that, because that's an implementation detail of Architecture Components library. Most possibly you should come up with a better solution as a result of adapting your use-case to match guidelines/contracts exposed by ViewModel
s API.
Nevertheless, let's examine possibilities of doing that.
Here's the code, that we should use in order to obtain a ViewModel
implementation:
val viewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)
What will this code result in, is that it will create an instance of HolderFragment
, which is a retained fragment, and will attach it to this
's fragment manager (might be either FragmentActivity
's fragment manager or Fragment
's child fragment manager).
This HolderFragment
will be added with a HolderFragment.HOLDER_TAG
, thus we are able to get an instance of this fragment from the fragment manager.
val holderFragment = supportFragmentManager.findFragmentByTag("android.arch.lifecycle.state.StateProviderHolderFragment") as HolderFragment
It's the HolderFragment
, that creates an instance of ViewModelStore
and keeps that instance as a private field. There exists a getter for that field, but there does not exist a setter, which means, that the only way to "substitute" this object is by using reflection.
But before doing that, let's try to write a custom implementation of ViewModelStore
class:
class MyViewModelStore : ViewModelStore() {
private val mMap = HashMap<String, ViewModel>()
internal fun put(key: String, viewModel: ViewModel) {
val oldViewModel = mMap.put(key, viewModel)
oldViewModel?.onCleared() // COMPILATION ERROR -> Cannot access 'onCleared': it is protected/*protected and package*/ in 'ViewModel'
}
internal operator fun get(key: String): ViewModel? {
return mMap[key]
}
override fun clear() {
for (vm in mMap.values) {
vm.onCleared() // COMPILATION ERROR -> Cannot access 'onCleared': it is protected/*protected and package*/ in 'ViewModel'
}
mMap.clear()
}
}
Unfortunately, we cannot do that, because ViewModel#onCleared()
has a protected
package access, which makes impossible for us call it outside of the android.arch.lifecycle
package. Again, we can use reflection to do that (but how good is that?).
Despite being not advised (by me), seems like that's also not achievable to do (without using reflection).
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