Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the differences between ViewModelProvider.Factory and ViewModelProvider.NewInstanceFactory?

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:

  1. What are the differences between ViewModelProvider.Factory and ViewModelProvider.NewInstanceFactory?
  2. Why they are being used like the codes mentioned above?
  3. What is the best practice/scenario to use each of them?
like image 909
Carter Chen Avatar asked Sep 23 '18 15:09

Carter Chen


People also ask

What is ViewModelProvider factory?

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.

What is the difference between ViewModelProvider and Viewmodelproviders?

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.

What is the use of ViewModelProvider?

Creates ViewModelProvider , which will create ViewModels via the given Factory and retain them in the given store . ViewModelStore : ViewModelStore where ViewModels will be stored.


2 Answers

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.

like image 97
Steru Avatar answered Oct 05 '22 15:10

Steru


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.

like image 20
livemaker Avatar answered Oct 05 '22 13:10

livemaker