ViewModelProvider.Factory 和 ViewModelProvider.NewInstanceFactory 有啥区别?

Posted

技术标签:

【中文标题】ViewModelProvider.Factory 和 ViewModelProvider.NewInstanceFactory 有啥区别?【英文标题】:What are the differences between ViewModelProvider.Factory and ViewModelProvider.NewInstanceFactory?ViewModelProvider.Factory 和 ViewModelProvider.NewInstanceFactory 有什么区别? 【发布时间】:2019-02-27 06:49:53 【问题描述】:

我目前正在将我的项目架构从 MVP 转变为 MVVM。当我在处理它时,我发现有些事情让我感到困惑:

在项目iosched的ScheduleViewModelFactory.kt中,工厂实现了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")
    

在来自codelab的项目Sunshine的DetailViewModelFactory.java中,工厂扩展了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);
    

我想知道:

    ViewModelProvider.FactoryViewModelProvider.NewInstanceFactory 有什么区别? 为什么要像上面提到的代码那样使用它们? 使用它们的最佳做法/场景是什么?

【问题讨论】:

【参考方案1】:

ViewModelProvider.Factory 和 ViewModelProvider.Factory 有什么区别 ViewModelProvider.NewInstanceFactory?

为什么要像上面提到的代码那样使用它们?

基于 ViewModelProvider 文档:

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);
            
        
    
    (...)

并考虑geeksforgeeks 对newInstance() 的描述:

一般来说new操作符是用来创建对象的,但是如果我们想 决定在运行时创建的对象类型,我们没有办法 使用新运算符。在这种情况下,我们必须使用 newInstance() 方法。

我假设NewInstanceFactoryFactory 的实现,当我们想要创建不同类型的视图模型时可以使用它。


另一方面,在 google 的 android-architecture/todoapp 中有:

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());
    

他们正在使用NewInstanceFactory,但是覆盖了create 方法!据我了解,如果我们覆盖它,与使用常规的Factory 没有区别。

【讨论】:

" 但是重写了 create 方法!据我了解,如果我们重写它,与使用常规工厂没有区别”——为什么这么说? 因为NewInstanceFactory 所做的唯一事情就是实现create() 方法。如果 google 使用 NewInstanceFactory 但覆盖了 create() 方法,那么他们可能一开始就使用常规的 Factory【参考方案2】:

ViewModelProvider.Factory 负责创建你的实例 视图模型。

如果您的 ViewModel 有依赖项,并且您想测试您的 ViewModel,那么您应该创建自己的 ViewModelProvider.Factory 并通过 ViewModel 构造函数传递依赖项,并为 ViewModelProvider.Factory 实例赋值。

何时使用 ViewModelProvider.Factory?

如果您的 ViewModel 有依赖项,那么您应该通过构造函数传递此依赖项(这是传递依赖项的最佳方式),因此您可以模拟该依赖项并测试您的 ViewModel。

何时不使用 ViewModelProvider.Factory

如果您的 ViewModel 没有依赖项,那么您将不需要创建自己的 ViewModelProvider.Factory。默认实现足以为您创建 ViewModel。

详情请浏览blog。

【讨论】:

以上是关于ViewModelProvider.Factory 和 ViewModelProvider.NewInstanceFactory 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章