前言
说起Android开发架构模式,相信很多人都不陌生,一般都能说的上来MVP,MVC,MVVM等架构模式,说起他们的区别,大多数人也能说出一二,无非是不同层之间的解耦,保持的职责单一的开发原则,增强其可扩展性等方便。 而今天要说到的,就是MVVM架构开发模式以及ViewModel的功能组件。
基本使用
- 引用ViewModel
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.2.0'
- 自定义的VM类只要继承引用的第三方库中的ViewModel抽象类即可
class MyViewModel: VideModel{
}
- 然后我们就可以在activity/fragment中实例化它
viewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)
viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
Tip:为什么Google抛弃了ViewModelProviders的构造方法,而换成了新的API。 原因是由于以往开发中通过依赖lifecycle-extensions库,间接的依赖了lifecycle-viewmodel库及相关系列库。随着JetPack组件的升级,lifecycle库也将拆分的更加低耦合,可以在某种程度,减少包体体积。
生命周期
Google官方给的生命周期图
- 生命周期长于Activity。不难发现,ViewModel的生命周期,贯穿整个被绑定的Activity的生命周期,也就是说,既然Activity因为系统配置变更销毁重建,比如旋转屏幕等,ViewModel对象依旧会被保留,并关联到新的Activity。只有当Activity正常销毁时,ViewModel对象才会调用onCleared()进行清除。
- 开头说过,众多开发模式当中,他们的区别大同小异,都是为了实现解耦。而我们知道,在MVP的Presenter中,需要持有View的接口对象,来回调结果给界面。而ViewModel是不需要持有UI层的引用,由于ViewModel贯穿了Activity的整个完整的生命周期,甚至比Activity生命周期要长,这就导致,如果让ViewModel持有Activity的引用时,容易造成内存泄漏等问题。
Tip:当ViewModel一定需要context引用,有没有什么办法呢? 其实是有的, ViewModel抽象类有一个实现类AndroidViewModel(Application),它接收的对象是application。
分析
我们知道ViewModel能在Activity和Fragment里使用,因此也能作为媒介使得Activity和Fragment进行交互。那么需要在View里使用呢? 假如我有一个自定义view或者dialog,它包含一堆数据和状态,能否使用ViewModel去管理数据呢? 这个是肯定的!后续会给到答案。 先来看看ViewModel的源码,为什么说到ViewModel创建不建议通过new,而是ViewModelProvider的方式。
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: ViewModelProvider.NewInstanceFactory.getInstance());
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull ViewModelProvider.Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();,
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
......
return (T) viewModel;
}
......
......
viewModel = (mFactory).create(modelClass);
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
从源码可以看出,ViewModel对象是通过工厂模式进行创建的,并且保存了Factory和缓存对象,当我们通过ViewModelProvider(this).get()方法获取ViewModel对象时,会优先通过缓存获取。
在看看注释6处的getDefaultViewModelProviderFactory()方法
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
......
if (mDefaultFactory == null) {
mDefaultFactory = new SavedStateViewModelFactory(
getApplication(),
this,
getIntent() != null ? getIntent().getExtras() : null);
}
return mDefaultFactory;
}
public SavedStateViewModelFactory(@NonNull Application application,
@NonNull SavedStateRegistryOwner owner,
@Nullable Bundle defaultArgs) {
mSavedStateRegistry = owner.getSavedStateRegistry();
mLifecycle = owner.getLifecycle();
mDefaultArgs = defaultArgs;
mApplication = application;
mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
......
return mFactory.create(modelClass);
......
}
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private static ViewModelProvider.AndroidViewModelFactory sInstance;
@NonNull
public static ViewModelProvider.AndroidViewModelFactory getInstance(@NonNull Application application) {
if (sInstance == null) {
sInstance = new ViewModelProvider.AndroidViewModelFactory(application);
}
return sInstance;
}
private Application mApplication;
public AndroidViewModelFactory(@NonNull Application application) {
mApplication = application;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
try {
return modelClass.getConstructor(Application.class).newInstance(mApplication);
}
......
}
return super.create(modelClass);
}
}
能看出AndroidViewModelFactory这个工厂,用单例模式创建了该工厂对象,然后使用工厂方法设计模式创建了ViewModel对象,ViewModel创建时传入的时Application参数,这里能够知道ViewModel对象最终持有的,并不是Activity的引用,而是Application的引用,也就是说,为什么ViewModel不容易造成内存泄漏的问题了。 到了这里,为什么不推荐使用new 去创建ViewModel也就迎刃而解了。
自定义view中,如果需要使用ViewModel,虽然官方不建议使用new ViewModel的方式,但是我们还是可以取巧,通过这种方式在view当中去使用它。- -!
|