I have a small app where one ViewModel
has been shared between Fragment
and FragmentDialog
. It shares not only logic, but also a state. It works fine until I have added one more fragment which uses the same ViewModel
. The issue is when I trigger a method of the ViewModel
this method is called, but its viewModelScoped
doesn't.
At first I thought it caused by ViewModel
's onCleared()
call somewhere during runtime. Indeed, onCleared()
is called when the first Fragment
replaced by the second Fragment
. However, when the call of my method is happened ViewModel
is still here (not null) and its viewModelScope
should be too, isn't it?
Later I noticed a recommendation to pass a parent Activity
as a context for a ViewModelFactory
- because I have single Activity
, ViewModelStoreOwner
would be the same for all fragments. It works, but I still concern about root cause of this issue and possible alternative solutions. Single activity is not an always option for many android apps.
public class ViewModelFactory implements ViewModelProvider.Factory {
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> viewModels;
@Inject
public ViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> viewModels) {
this.viewModels = viewModels;
}
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
Provider<ViewModel> viewModelProvider = viewModels.get(modelClass);
if (viewModelProvider == null) {
throw new IllegalArgumentException("model class " + modelClass + " not found");
}
return (T) viewModelProvider.get();
}
}
@Module
public abstract class ViewModelModule {
@Binds
abstract ViewModelProvider.Factory bindViewModelFactory(ViewModelFactory viewModelFactory);
@Binds
@IntoMap
@ViewModelKey(DashboardViewModel.class)
@Singleton
abstract ViewModel dashboardViewModel(DashboardViewModel vm);
}
viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(DashboardViewModel::class.java)
/*DashboardViewModel class*/ {
fun addItem() {
Log.d(App.TAG, "Add item has started")
viewModelScope.launch {
Log.d(App.TAG, "Add item coroutine has started")
// ...
}
If you have any good thoughts on this, please share.