问题
As I understand when we call this code in fragments, we will have a viewmodel instance from activity ViewModelStore:
viewModel = ViewModelProviders.of(activity!!).get(SharedViewModel::class.java)
When fragments will end their lifecycle, the instance of this viewmodel will exist in ViewModelStore until the destruction of activity. ViewModelStore has a clear() method, but it clears all viewmodels in it. Is there some way to clear specific ViewModel?
Another solution is to scope ViewModel to parent fragment, but how do we initialize ViewModel in another fragment through ViewModelProviders.of()? Should I pass fragment or viewmodel instance to the next fragment?
回答1:
There is a hacky way to clear a specific ViewModel
instance in which you should create your ViewModel
instance with a customized key
as stated below, and in order to clear it you should just create another instance (with different ViewModel
class such as an EmptyViewModel
class) but with the same key
.
ShopFragment class:
class shopFragment : BaseFragment() {
fun getViewModel() : ShopViewModel {
return ViewModelProviders.of(activity!!).get(ShopViewModel.KEY, ShopViewModel::class.java)
}
fun clearViewModel() {
ViewModelProviders.of(activity!!).get(ShopViewModel.KEY, EmptyViewModel::class.java)
}
// Fragment logic ...
}
ShopViewModel class:
class ShopViewModel(application: Application) : AndroidViewModel(application) {
companion object {
const val KEY = "ShopViewModel"
}
// view model logic ...
}
EmptyViewModel which is a dummy ViewModel class:
class EmptyViewModel() : ViewModel() {
// A dummy view model!
}
And the magic is happening inside ViewModelProvider
class of androidx.lifecycle
dependecy, the trick here is revealed when you take a look at the get()
function of ViewModelProvider
class which retrieves your previous ViewModel
instance and compares it with the EmptyViewModel
class and as they are not the same, it run mViewModelStore.put(key, viewModel);
:
public class ViewModelProvider {
//...
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
// ...
}
As stated below inside ViewModelStore
class of the androidx.lifecycle
dependency, the put()
method will retrieve the ShopViewModel
and clear it, and replace EmptyViewModel
instance.
public class ViewModelStore {
//...
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
//...
}
来源:https://stackoverflow.com/questions/55092532/how-to-manually-clear-a-specific-viewmodel