I'm currently transforming my project architecture from MVP to MVVM. When I'm working on it, I find something made me confused:
In ScheduleViewModelFactory.kt
of project iosched, the factory implements ViewModelProvider.Factory:
class ScheduleViewModelFactory(
private val userEventRepository:DefaultSessionAndUserEventRepository
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(ScheduleViewModel::class.java)) {
return ScheduleViewModel(LoadUserSessionsByDayUseCase(userEventRepository)) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
In DetailViewModelFactory.java
of project Sunshine from codelab, the factory extends ViewModelProvider.NewInstanceFactory:
public class DetailViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private final SunshineRepository mRepository;
private final Date mDate;
public DetailViewModelFactory(SunshineRepository repository, Date date) {
this.mRepository = repository;
this.mDate = date;
}
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
//noinspection unchecked
return (T) new DetailActivityViewModel(mRepository, mDate);
}
}
I would like to know:
ViewModelProvider. Factory which may create AndroidViewModel and ViewModel , which have an empty constructor. Simple factory, which calls empty constructor on the give class. Implementations of Factory interface are responsible to instantiate ViewModels.
So, you can think of as wrapper around library class for ViewModelProvider . On the other hand, ViewModelProvider (belongs to Maven artifact android. arch. lifecycle:viewmodel) is class that provides ViewModels for a scope.
Creates ViewModelProvider , which will create ViewModels via the given Factory and retain them in the given store . ViewModelStore : ViewModelStore where ViewModels will be stored.
What are the differences between ViewModelProvider.Factory and ViewModelProvider.NewInstanceFactory?
Why they are being used like the codes mentioned above?
Basing on ViewModelProvider documentation:
public class ViewModelProvider {
/**
* Implementations of {@code Factory} interface are responsible to instantiate ViewModels.
*/
public interface Factory {
@NonNull
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
(...)
/**
* Simple factory, which calls empty constructor on the given class.
*/
public static class NewInstanceFactory implements Factory {
@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
}
(...)
}
and taking geeksforgeeks description of newInstance()
into consideration:
In general, new operator is used to create objects, but if we want to decide type of object to be created at runtime, there is no way we can use new operator. In this case, we have to use newInstance() method.
I assume the NewInstanceFactory
is an implementation of the Factory
, which can be used when we want to create ViewModels of different types.
On the other hand, in google's android-architecture/todoapp there is:
public class ViewModelFactory extends ViewModelProvider.NewInstanceFactory {
(...)
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
if (modelClass.isAssignableFrom(StatisticsViewModel.class)) {
//noinspection unchecked
return (T) new StatisticsViewModel(mApplication, mTasksRepository);
} else if (modelClass.isAssignableFrom(TaskDetailViewModel.class)) {
//noinspection unchecked
return (T) new TaskDetailViewModel(mApplication, mTasksRepository);
} else if (modelClass.isAssignableFrom(AddEditTaskViewModel.class)) {
//noinspection unchecked
return (T) new AddEditTaskViewModel(mApplication, mTasksRepository);
} else if (modelClass.isAssignableFrom(TasksViewModel.class)) {
//noinspection unchecked
return (T) new TasksViewModel(mApplication, mTasksRepository);
}
throw new IllegalArgumentException("Unknown ViewModel class: " + modelClass.getName());
}
}
They are using the NewInstanceFactory
, but are overriding the create
method! To my understanding, if we override it, there's no difference from using a regular Factory
.
ViewModelProvider.Factory is responsible to create your instance of ViewModel.
If your ViewModel have dependencies and you want to test your ViewModel then you should create your own ViewModelProvider.Factory and passed dependency through ViewModel constructor and give value to the ViewModelProvider.Factory instance.
When to use ViewModelProvider.Factory?
If your ViewModel have dependencies then you should pass this dependencies through the constructor (It is the best way to pass your dependencies), so you can mock that dependencies and test your ViewModel.
When not to use ViewModelProvider.Factory
If your ViewModel have no dependencies then you will not require to create your own ViewModelProvider.Factory. The default implementation is enough to create ViewModel for you.
Please go through this blog for details.
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