概念

试图数据管理类,ViewModel负责准备和管理跟UI组件(Activity,Fragment)相关的数据类,同时还可以用来负责UI组件间的通信。

存在的意义

a.页面销毁重新创建后(如旋转屏幕,异常销毁等),原来的UI相关数据会丢失,理论上可以通过onSaveInstanceState()存储数据,组件重建之后通过onCreate(),从中读取Bundle恢复数据。但如果是大量数据,Intent源码限制1M大小,实际可用大概512k左右,超过时不能储存。

b.基于架构层次考虑,UI controllers其实只需要负责展示UI数据、响应用户交互和系统交互,但是现存MVP架构中presenter层过于庞大,Aciivity与Fragment也难以做到试图分类。

生命周期:

     左侧表示Activity的生命周期状态,右侧绿色部分表示ViewModel的生命周期范围。ViewModel只有onCleared()在结束时调用,Activity生命周期照旧。注意当旋转屏幕时,在不设置onConfig属性的情况下,Activity会被reCreate,但是VidewModel还是之前的对象,没有重新创建。

ViewModel原理

1.创建

a.viewModel初始化通过ViewModelProvider获取ViewModel实例,先看ViewModel源码其构造方法:

public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {

        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory

                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()

                : NewInstanceFactory.getInstance());

}

    

public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {

    this(owner.getViewModelStore(), factory);

}

ViewModelProvider的构造方法中可以看到最终是需要两个参数ViewModelStoreOwner以及Factory。这两个参数中ViewModelStoreOwner是用来存储ViewModel对象的,Factory是用来创建ViewModel对象。

b.ViewModelProvider的get()方法获取ViewModel实例

public T get(@NonNull String key, @NonNull Class modelClass) {

        ViewModel viewModel = mViewModelStore.get(key); // 1.是否有缓存ViewModel实例缓存

        ...

        if (mFactory instanceof KeyedFactory) {

            viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);

        } else {

            viewModel = (mFactory).create(modelClass);

        }

        mViewModelStore.put(key, viewModel);

        return (T) viewModel;

    }

通过Factory创建ViewModel后,讲viewModel放置在mViewModelStore缓存中

c.ViewModelStoreOwner,ViewModelStore

public interface ViewModelStoreOwner {

/**

* Returns owned {@link ViewModelStore}

*

* @return a {@code ViewModelStore}

*/

@NonNull

ViewModelStore getViewModelStore();

}

public class ViewModelStore {

private final HashMap mMap = new HashMap<>();

final void put(String key, ViewModel viewModel) {

ViewModel oldViewModel = mMap.get(key);

if (oldViewModel != null) {

oldViewModel.onCleared();

}

mMap.put(key, viewModel);

}

final ViewModel get(String key) {

return mMap.get(key);

}

public final void clear() {

for (ViewModel vm : mMap.values()) {

vm.onCleared();

}

mMap.clear();

}

}

源码中我们传入的组件ViewModelStoreOwner,通过getViewModelStore方法获取到的ViewModelStore对象,从源码中我们能够看到,在ViewModelStore内部是保存了一个HashMap,key就是ViewModel的全类名,所以在调用get方法时,从store拿到的ViewModel就是我们要创建的这个实例

2.销毁

a.ViewModel中有clear()方法和onCleared()都执行了clear方法,进行vm.clear与清除缓存HashMap缓存的 操作

public final void clear() {

        for (ViewModel vm : mMap.values()) {

            vm.clear();

        }

        mMap.clear();

    }

b.继续跟踪代码能查看到Activity与Framgent执行getViewModelStore().clear()方法的时机

public ComponentActivity() {

getLifecycle().addObserver(new LifecycleEventObserver() {

@Override

public void onStateChanged(@NonNull LifecycleOwner source,

@NonNull Lifecycle.Event event) {

if (event == Lifecycle.Event.ON_DESTROY) {

if (!isChangingConfigurations()) {

// 销毁ViewModel

getViewModelStore().clear();

}

}

}

});

}

void clearNonConfigState(@NonNull Fragment f) {

...

// Clear and remove the Fragment's ViewModelStore

ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);

if (viewModelStore != null) {

// ViewModel销毁

viewModelStore.clear();

mViewModelStores.remove(f.mWho);

}

}

这里有个点需要注意,ViewModel的销毁在onDestory()中,是晚于onDestoryView()的,所以要注意在使用ViewModel做操作时会不会触发组件更新。不然的话可能造成空指针异常。

3.ViewModel的缓存策略

在Activity重建时会执行destory生命周期事件,那么为什么ViewModel没有销毁呢?

public ViewModelStore getViewModelStore() {

...

if (mViewModelStore == null) {

NonConfigurationInstances nc =

(NonConfigurationInstances) getLastNonConfigurationInstance();

if (nc != null) {

// Restore the ViewModelStore from NonConfigurationInstances

mViewModelStore = nc.viewModelStore;

}

if (mViewModelStore == null) {

mViewModelStore = new ViewModelStore();

}

}

return mViewModelStore;

}

getViewModelStore()方法时优先从getLastNonConfigurationInstance()方法获取,如果getLastNonConfigurationInstance()方法没有缓存,才会去新建对象。

NonConfigurationInstances 持有并储存viewModelStore对象,viewModelStore对象的HashMap中存储ViewModel对象。

4.Fragment之间共享ViewModel

inline fun Fragment.activityViewModels(

noinline factoryProducer: (() -> Factory)? = null

) = createViewModelLazy(VM::class, { requireActivity().viewModelStore },

factoryProducer ?: { requireActivity().defaultViewModelProviderFactory })

在activityViewModels()的实现中可以看到是requireActivity()获取的viewModelStore。以此来实现共享ViewModel。

相关文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: