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.
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).