ViewModel(Factory 与 key)

一 为什么要学习ViewModel自定义实例?

那么你可能会疑问了,使用 ViewModelProviders.of(getActivity()).get(ViewModel.class); 创建ViewModel这么简单轻松,为什么还要自己构建Factory呢。原因有以下几点:

  1. 如果你继承的ViewModel类是有参构造,那么上面这个方式是不支持在实例ViewModel的传参的,所以需要自己构建Factory类
  2. 一个Activity可能根据业务会有多个不同的ViewModel,那么根据不同的业务下配置不同的ViewModel,需要自己构建Factory类,来根据类别返回不同的ViewModel给外部(这也是工厂模式的核心,解决接口选择的问题)

二 了解ViewModel的构建原理

  因为后续的使用ViewModelProvider.Factory创建ViewModel,所以我们必需了解一些些ViewModel构建、保存、移除原理。好在有一个参照物可以阅读理解,那就是上面提到以 ViewModelProviders 形式的构建ViewModel。对照着它看基本上就能明白一些东西了。

1 iewModelProviders.of()

我们点击进入源码后可以看到如下代码

   @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity) {
        return of(activity, null);
    }

恩,of又去调用了一个重载的of,但是传入了一个activity或者Fragment 和 一个null ,我们看看这个2个参数的of干了什么

    @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity,
            @Nullable Factory factory) {
        Application application = checkApplication(activity); //源码在这里检查了一下activity的application
        if (factory == null) {
            //它拿application去创建了一个Factory类
            //这个factory其实就是构建ViewModel的工厂类
            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application); 
        }
         //实例化了一个ViewModelProvider,
         //在activity里取得ViewModelStore(这个东西是用于保存ViewModel使用的),也传入了
         //并且也把Factory类一起传入
         //其实ViewModelStore和factory传入后就直接成为成员变量缓存了,等待你调用get方法来创建ViewModel
        return new ViewModelProvider(activity.getViewModelStore(), factory);
    }

我们可以看看ViewModelProvider.AndroidViewModelFactory.getInstance(application) 这行代码

    private static AndroidViewModelFactory sInstance;

        /**
         * Retrieve a singleton instance of AndroidViewModelFactory.
         *
         * @param application an application to pass in {@link AndroidViewModel}
         * @return A valid {@link AndroidViewModelFactory}
         */
        @NonNull
        public static AndroidViewModelFactory getInstance(@NonNull Application application) {
            if (sInstance == null) {
                sInstance = new AndroidViewModelFactory(application);
            }
            return sInstance;
        }

可以看到,直接给你了一个有Application的全局单例的Factory类。

2 ViewModelProviders.of().get()

get()方法其实就是实现了 factory 创建 与 ViewModelStore保存 ViewModel,并且返回ViewModel

    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
        String canonicalName = modelClass.getCanonicalName(); //获取了传入的实现的ViewModel的类名
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        //因为我们没有传入key,所以这里直接用类名取代的成为了key
        //然后就进入下面这个重载的get方法里进行实现了
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass); 
    }

    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        ViewModel viewModel = mViewModelStore.get(key);//去查找这个ViewModelStore 对应key的保存viewModel

        if (modelClass.isInstance(viewModel)) { //检查一下这个viewModel是不是已经实例化,不是null
            //noinspection unchecked
            return (T) viewModel;  //如果已经实例化,不等于null就直接返回
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        //下面就用传入的Factory类来实例化你需要的ViewModel
        if (mFactory instanceof KeyedFactory) { //这里检查是不是带key
            viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
        } else {
            viewModel = (mFactory).create(modelClass); //这里的create使用了反射的形式创建实例
        }
        mViewModelStore.put(key, viewModel); //然后存一下ViewModel
        //noinspection unchecked
        return (T) viewModel; //返回viewModel
    }

移除缓存的ViewModel

  其实蛛丝马迹就在ViewModelStore里

public class ViewModelStore {

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

    final ViewModel get(String key) {
        return mMap.get(key);
    }

    Set<String> keys() {
        return new HashSet<>(mMap.keySet());
    }

    /**
     *  Clears internal storage and notifies ViewModels that they are no longer used.
     */
    public final void clear() { //这里清理了当前Activity或者Fragment的所有ViewModel,这个方法是在Activity或者Fragment在销毁的时候有调用的
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

三 使用ViewModelProvider.Factory实现创建ViewModel

 使用反射创建无参实例(在上面的源码上可以看到的创建方式,这样一个Factory就可以传入继承ViewModel的泛型,加以实例)

public class MainViewModelFactory implements ViewModelProvider.Factory {
    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        try {
            return modelClass.newInstance(); //使用newInstance反射实例ViewModel,并且传出去
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return null;

    }
}

使用MainViewModelFactory创建ViewModel,注意!千万别自己就使用Factory直接创建ViewModel,因为上面的get()源码里说明了,这个ViewModel是还需要保存到ViewModelStore里面的,而ViewModelStore的put方法是私有方法。所以我们还是需要交给ViewModelProviders.of().get();来创建让它帮我们保存到ViewModelStore里,代码如下:

    private MainViewModel mMainViewModel;
    private void initViewModel() {
        MainViewModelFactory mainViewModelFactory = new MainViewModelFactory();
        mMainViewModel = ViewModelProviders.of(this, mainViewModelFactory).get(MainViewModel.class);
}
使用反射创建有参实例
public class MainViewModelFactory4 implements ViewModelProvider.Factory {
    private String mValue;

    public MainViewModelFactory4(String value){
        mValue = value;
    }

    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        try {
            Class[] parameterTypeArray = new Class[]{String.class};
            return modelClass.getConstructor(parameterTypeArray).newInstance(mValue);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;

    }
}

还是跟上面一样使用ViewModelProviders.of().get();来创建。

简单暴力直接实例目标ViewModel

public class MainViewModelFactory implements ViewModelProvider.Factory {
    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        MainViewModel mainViewModel = new MainViewModel();
        mainViewModel.setContent("设置初始化值"); 
        return (T)mainViewModel;

    }
}

还是跟上面一样使用ViewModelProviders.of().get();来创建。

四 使用KEY创建ViewModel

这没啥好说的,就是根据不同的key创建独立数据与内存地址的ViewModel,他们之间数据不互通。

 mMainViewModel1 = ViewModelProviders.of(this).get("1", MainViewModel.class);
        mMainViewModel2 = ViewModelProviders.of(this).get("2", MainViewModel.class);
        mMainViewModel3 = ViewModelProviders.of(this).get("3", MainViewModel.class);

五 关于ViewModelProvider.NewInstanceFactory

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

六 关于ViewModelProvider.AndroidViewModelFactory

带application的工厂类,你需要配置一个需要application的ViewModel,可以直接使用这个单例的AndroidViewModelFactory。可以看源码(下面的代码上面已经贴了一部分了,这里贴全),需要一个构造方式是传入application的ViewModel:

public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {

        private static AndroidViewModelFactory sInstance;

        /**
         * Retrieve a singleton instance of AndroidViewModelFactory.
         *
         * @param application an application to pass in {@link AndroidViewModel}
         * @return A valid {@link AndroidViewModelFactory}
         */
        @NonNull
        public static AndroidViewModelFactory getInstance(@NonNull Application application) {
            if (sInstance == null) {
                sInstance = new AndroidViewModelFactory(application);
            }
            return sInstance;
        }

        private Application mApplication;

        /**
         * Creates a {@code AndroidViewModelFactory}
         *
         * @param application an application to pass in {@link AndroidViewModel}
         */
        public AndroidViewModelFactory(@NonNull Application application) {
            mApplication = application;
        }

        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
                //noinspection TryWithIdenticalCatches
                try {
                    return modelClass.getConstructor(Application.class).newInstance(mApplication);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (InstantiationException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                }
            }
            return super.create(modelClass);
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值