前言
ViewModel的虽然可以以很简单方便的 ViewModelProviders.of(getActivity()).get(ViewModel.class); 但是这只是google提供的简单构建,你需要引入下面的库才能使用:
implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"
但是!远远不止这样。l还可以使用ViewModelProvider.Factory自定义实例ViewModel(其实继承工厂类实例ViewModel才是google推荐的,这点在Android studio的模板代码里可以看到)
转载请注明来源:https://www.cnblogs.com/guanxinjing/p/12198971.html
为什么要学习ViewModel自定义实例?
那么你可能会疑问了,使用 ViewModelProviders.of(getActivity()).get(ViewModel.class); 创建ViewModel这么简单轻松,为什么还要自己构建Factory呢。原因有以下几点:
- 如果你继承的ViewModel类是有参构造,那么上面这个方式是不支持在实例ViewModel的传参的,所以需要自己构建Factory类
- 一个Activity可能根据业务会有多个不同的ViewModel,那么根据不同的业务下配置不同的ViewModel,需要自己构建Factory类,来根据类别返回不同的ViewModel给外部(这也是工厂模式的核心,解决接口选择的问题)
了解ViewModel的构建原理
因为后续的使用ViewModelProvider.Factory创建ViewModel,所以我们必需了解一些些ViewModel构建、保存、移除原理。好在有一个参照物可以阅读理解,那就是上面提到以 ViewModelProviders 形式的构建ViewModel。对照着它看基本上就能明白一些东西了。
看看 ViewModelProviders.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类。
接下来看看ViewModelProviders.of().get() 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
也是继承Factory,然后帮你实现了newInstance();如果你只是简简单单实例一个ViewModel,可以直接继承这个,我们可以看源码:
/**
* Simple factory, which calls empty constructor on the give 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);
}
}
}
关于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);
}
}
End
本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/12198971.html
本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
来源:https://www.cnblogs.com/guanxinjing/p/12198971.html |