问题
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