android viewModel源码分析
ViewModel是google官方的MVVM架构组件,目前已经集成到了最新的支持库中了,是MVVM架构的核心组件之一,ViewModel是把View和Model关联起来的加工厂。
ViewModel类是被设计用来以可感知生命周期的方式存储和管理 UI 相关数据。ViewModel中数据会一直存活即使 Activity Configuration发生变化。
viewModel可以解决以下痛点:
1.数据持久化
在系统销毁和重建Activity时,涉及到数据保存问题,显示重新请求或者加载数据是不友好的.使用 Activity 的onSaveInstanceState()机制保存和恢复数据缺点明显,只适合保存少量可以被序列化,反序列化数据,对于列表型这种庞大的数据类型并不适合,利用VeiwModel的存活机制可以解决此痛点.
2.异步请求回调易引发内存泄露
app通常需要频繁异步请求数据,在activity或者fargment中接收数据回调,就要在销毁时对其进行清理,避免内存泄露,随着项目扩大,维护成本增加.但利用ViewModel处理数据,可以解决.
3.分担UI负担,职责分明
UI Controller 比如 Activity 、Fragment 是设计用来渲染展示数据、响应用户行为、处理系统的某些交互,不应处理数据逻辑,我们可以分离出数据操作的职责给 ViewModel
4.Fragment 间数据共享
比如在一个 Activity 里有多个 Fragment,这 Fragment 之间需要做某些交互。我之前的做法是接口回调,需要统一在 Activity 里管理,并且不可避免的 Fragment 之间还得互相持有对方的引用.
我们可以利用ViewModel的作用域机制共享数据.
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// Update the UI.
});
}
}
1. ViewModel的创建
ViewModel vm = ViewModelProviders.of(getActivity()).get(getModelClass())
对上面代码拆分:
ViewModelProvider provider = ViewModelProviders.of(getActivity());
ViewModel vm = provider.get(getModelClass());
进入ViewModelProvider.of(getActivity());
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
// 传入 activity 和 null Factory
return of(activity, null);
}
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
// 获取 application
Application application = checkApplication(activity);
// factory为null , 创建默认的 AndroidViewModelFactory
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
// 创建 ViewModelProvider(ViewModelStore , factory)
return new ViewModelProvider(ViewModelStores.of(activity), factory);
}
进入ViewModelProvider 的 get(class);方法
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
// 包含路径的类名
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
// 根据canonicalName生成 key
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
// 根据 key 从mViewModelStore中获取 ViewModel
ViewModel viewModel = mViewModelStore.get(key);
// viewModle不为空,并且是modelClass类型,则返回viewModel
if (modelClass.isInstance(viewModel)) {
return (T) viewModel;
} else {
if (viewModel != null) {
}
}
// 根据传入的工厂类创建ViewModel(这里就是viewModel的最终创建)
viewModel = mFactory.create(modelClass);
// 将viewModel缓存到VeiwModelStore中
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
从上面源码中可以看出,ViewModel的创建是由传入的ViewModelFactory创建的
在这里ViewModelFactory 是默认的
// factory为null , 创建默认的 AndroidViewModelFactory
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private static AndroidViewModelFactory sInstance;
// 单例
public static AndroidViewModelFactory getInstance(@NonNull Application application) {
if (sInstance == null) {
sInstance = new AndroidViewModelFactory(application);
}
return sInstance;
}
private Application mApplication;
public AndroidViewModelFactory(@NonNull Application application) {
mApplication = application;
}
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
// modelClass 属于AndroidViewModel则传入mApplication创建AndroidViewModel
// 否则默认创建ViewModel
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
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);
}
}
小结:
viewModel的最终获取是在VeiwModelProvider的get(key,modleClass)方法中,
key是根据modelClass的全类名构建的。
第一步:从ViewModelStore中根据key获取与modleClass同类型的veiwModel,成功则返回
第二步:第一步失败,再通过ViewModelFactory创建,并缓存到viewModelStore中
所以viewModel的创建是由传入的ViewModleFactory创建的,然后缓存到ViewModelStore中
2.界面重建,ViewModel是如何保留的?
viewModel从ViewModelStore缓存获取,或者通过ViewModelFactory创建,
当界面重建需要复用viewModel,这时viewModel只能从viewModelStore缓存中获取,这样才能拿到相同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);
}
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
ViewModelStore里面维护了一个 map, key 就是modelClass全类型构建的字符串,value就是ViewModel。
viewModelStore是通过构造器传入VeiwModeProvider的
new ViewModelProvider(ViewModelStores.of(activity), factory)
ViewModelStores.of(activity)获取ViewModelStore对象
public class ViewModelStores {
private ViewModelStores() {
}
public static ViewModelStore of(@NonNull FragmentActivity activity) {
// 当前activity是ViewModelStoreOwner 则从activity中获取ViewModelStore
// 高版本的FragmentActivity已经实现 ViewModelStoreOwner,在这里只分析FragmentActivity
if (activity instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) activity).getViewModelStore();
}
return holderFragmentFor(activity).getViewModelStore();
}
// 当fragment是ViewModelStoreOwner 则从fragment中获取ViewModelStore
// 高版本的fragment已经实现 ViewModelStoreOwner,在这里只分析Fragment
public static ViewModelStore of(@NonNull Fragment fragment) {
if (fragment instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) fragment).getViewModelStore();
}
return holderFragmentFor(fragment).getViewModelStore();
}
}
① 下面分析,FragmentActivity中ViewModelStore是如何在界面重建时保留下来的
FragmentActivity 中
public class FragmentActivity{
...
protected void onCreate(@Nullable Bundle savedInstanceState) {
this.mFragments.attachHost((Fragment)null);
super.onCreate(savedInstanceState);
// 当系统重建时,首先从NonConfigurationInstances中获取ViewModelStore
// NonConfigurationInstances数据是在系统因配置发生改变(屏幕旋转),回调 onRetainNonConfigurationInstance()保存的
// 所以界面销毁和重建之后的viewModelStore是同一个
FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
if (nc != null && nc.viewModelStore != null && this.mViewModelStore == null) {
this.mViewModelStore = nc.viewModelStore;
}
....
}
public ViewModelStore getViewModelStore() {
if (this.getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the Application instance. You can't request ViewModel before onCreate call.");
} else {
if (this.mViewModelStore == null) {
// 当系统重建时,首先从NonConfigurationInstances中获取ViewModelStore
// NonConfigurationInstances数据是在系统因配置发生改变(屏幕旋转),回调onRetainNonConfigurationInstance()保存的
// 所以界面销毁和重建之后的viewModelStore是同一个
FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
if (nc != null) {
this.mViewModelStore = nc.viewModelStore;
}
if (this.mViewModelStore == null) {
this.mViewModelStore = new ViewModelStore();
}
}
return this.mViewModelStore;
}
}
// 系统因配置发生改变(屏幕旋转),回调onRetainNonConfigurationInstance()
// 返回一个NonConfigurationInstances 对象
// 当界面再次重建时,通过getLastNonConfigurationInstance()可以获取NonConfigurationInstances
public final Object onRetainNonConfigurationInstance() {
Object custom = this.onRetainCustomNonConfigurationInstance();
// 获取fragment 相关状态
FragmentManagerNonConfig fragments = this.mFragments.retainNestedNonConfig();
if (fragments == null && this.mViewModelStore == null && custom == null) {
return null;
} else {
FragmentActivity.NonConfigurationInstances nci = new FragmentActivity.NonConfigurationInstances();
nci.custom = custom;
// 保留viewModelStore
nci.viewModelStore = this.mViewModelStore;
// 保留 fragment相关状态----->fragment 的ViewModelStore的保留就是这里开始的
nci.fragments = fragments;
return nci;
}
}
...
}
小结:
从FragmentActivity.getViewModelStore()方法中可以看出,
ViewModelStore有三个地方可以赋值:
第一个地方:
界面重建场景使用:
在onCreate()中
通过 NonConfigurationInstances
this.mViewModelStore = FragmentActivity.getLastNonConfigurationInstance().viewModelStore;
当配置发生改变,系统销毁界面会回调 FragmentActivity.onRetainNonConfigurationInstance(),
此时缓存了ViewModel的ViewModelStore就会记录到NonConfigurationInstances中,
界面重建时,从NonConfigurationInstances取出ViewModelStore,所以界面销毁前和重建后的ViewModelStore是同一个,根据传入的modelClass构建key,就可以取出缓存的viewModel.
第二个地方:
在 getViewModelStore()中
也是 通过NonConfigurationInstances
this.mViewModelStore = FragmentActivity.getLastNonConfigurationInstance().viewModelStore;
第三个地方:
在getViewModelStore()中
第一次创建界面使用
this.mViewModelStore = new ViewModelStore();
直接创建全新的ViewModelStore对象
通过onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()机制,
实现对ViewModelStore的复用,从而保留VeiwModel对象
②下面分析Fragment中,viewModelStore是如何在界面重建保留下来的
public class ViewModelStores {
private ViewModelStores() {
}
...
// 当fragment是ViewModelStoreOwner 则从fragment中获取ViewModelStore
// 高版本的fragment已经实现 ViewModelStoreOwner,在这里只分析Fragment
public static ViewModelStore of(@NonNull Fragment fragment) {
if (fragment instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) fragment).getViewModelStore();
}
return holderFragmentFor(fragment).getViewModelStore();
}
}
Fragment中
public class Fragment {
...
public ViewModelStore getViewModelStore() {
if (this.getContext() == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
} else {
if (this.mViewModelStore == null) {
this.mViewModelStore = new ViewModelStore();
}
return this.mViewModelStore;
}
}
...
}
在fragment中貌似只有getViewModelStore()方法对mViewModelStore赋值.
前面分析FragmentActivity时,我们知道onRetainNonConfigurationInstance()有对fargment相关状态进行保留
public final Object onRetainNonConfigurationInstance() {
Object custom = this.onRetainCustomNonConfigurationInstance();
// 获取fragment 相关状态
FragmentManagerNonConfig fragments = this.mFragments.retainNestedNonConfig();
if (fragments == null && this.mViewModelStore == null && custom == null) {
return null;
} else {
FragmentActivity.NonConfigurationInstances nci = new FragmentActivity.NonConfigurationInstances();
nci.custom = custom;
// 保留viewModelStore
nci.viewModelStore = this.mViewModelStore;
// 保留 fragment相关状态----->fragment 的ViewModelStore的保留就是这里开始的
nci.fragments = fragments;
return nci;
}
}
进入FragmentController.retainNestedNonConfig();
public FragmentManagerNonConfig retainNestedNonConfig() {
// this.mHost.mFragmentManager是 FragmentManagerImpl
return this.mHost.mFragmentManager.retainNonConfig();
}
final class FragmentManagerImpl extends FragmentManager implements Factory2 {
...
FragmentManagerNonConfig retainNonConfig() {
setRetaining(this.mSavedNonConfig);
// FragmentManagerNonConfig mSavedNonConfig;
// 返回 成员变量 mSavedNonConfig ---> 存放了mViewModelStores
return this.mSavedNonConfig;
}
...
}
public class FragmentManagerNonConfig {
private final List<Fragment> mFragments;
private final List<FragmentManagerNonConfig> mChildNonConfigs;
private final List<ViewModelStore> mViewModelStores;
FragmentManagerNonConfig(List<Fragment> fragments, List<FragmentManagerNonConfig> childNonConfigs, List<ViewModelStore> viewModelStores) {
this.mFragments = fragments;
this.mChildNonConfigs = childNonConfigs;
this.mViewModelStores = viewModelStores;
}
...
}
可以看到FragmentManagerNonConfig mSavedNonConfig 里面存放了fragment列表和对应的viewModelStore,还有childFragment 的 FragmentManagerNonConfig
mSavedNonConfig是在FragmentActivity. onSaveInstanceState(Bundle outState)进行赋值的
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
this.markFragmentsCreated();
//final FragmentController mFragments = FragmentController.createController(new FragmentActivity.HostCallbacks());
Parcelable p = this.mFragments.saveAllState();
if (p != null) {
outState.putParcelable("android:support:fragments", p);
}
...
}
public class FragmentController{
public Parcelable saveAllState() {
return this.mHost.mFragmentManager.saveAllState();
}
}
final class FragmentManagerImpl extends FragmentManager implements Factory2 {
Parcelable saveAllState() {
...
if (this.mActive != null && this.mActive.size() > 0) {
...
if (!haveFragments) {
if (DEBUG) {
Log.v("FragmentManager", "saveAllState: no fragments!");
}
return null;
} else {
...
// 这里 对mSavedNonConfig 进行赋值
// mSavedNonConfig会在 FragmentActivity.onRetainNonConfigurationInstance()保留
this.saveNonConfig();
return fms;
}
} else {
return null;
}
}
// mSavedNonConfig赋值
void saveNonConfig() {
ArrayList<Fragment> fragments = null;
ArrayList<FragmentManagerNonConfig> childFragments = null;
ArrayList<ViewModelStore> viewModelStores = null;
if (this.mActive != null) {
// 遍历活跃的fragment
for(int i = 0; i < this.mActive.size(); ++i) {
Fragment f = (Fragment)this.mActive.valueAt(i);
if (f != null) {
// 当前fragment 是否保留实例
if (f.mRetainInstance) {
if (fragments == null) {
fragments = new ArrayList();
}
// 添加保留实例的fragment
fragments.add(f);
...
}
// childFragmen的相关状态
FragmentManagerNonConfig child;
if (f.mChildFragmentManager != null) {
// 保存childFragment 的状态
f.mChildFragmentManager.saveNonConfig();
child = f.mChildFragmentManager.mSavedNonConfig;
} else {
child = f.mChildNonConfig;
}
int j;
if (childFragments == null && child != null) {
childFragments = new ArrayList(this.mActive.size());
// 这里是为了 child在childFragments位置与当前f位置对应
for(j = 0; j < i; ++j) {
childFragments.add((Object)null);
}
}
if (childFragments != null) {
childFragments.add(child);
}
if (viewModelStores == null && f.mViewModelStore != null) {
viewModelStores = new ArrayList(this.mActive.size());
// 这里是为了 f.mViewModelStore在viewModelStores位置与当前f位置对应
for(j = 0; j < i; ++j) {
viewModelStores.add((Object)null);
}
}
// 添加mViewModelStore
if (viewModelStores != null) {
viewModelStores.add(f.mViewModelStore);
}
}
}
}
if (fragments == null && childFragments == null && viewModelStores == null) {
this.mSavedNonConfig = null;
} else {
// mSavedNonConfig 赋值
this.mSavedNonConfig = new FragmentManagerNonConfig(fragments, childFragments, viewModelStores);
}
}
}
现在我们已经知道FragmentActivity销毁时,在onRetainNonConfigurationInstance()中会保留fragmnet的相关状态,包括ViewModelStore。
接下来分析界面重建时,是如何将fragment 的ViewModelStore取出的.
protected void onCreate(@Nullable Bundle savedInstanceState) {
this.mFragments.attachHost((Fragment)null);
super.onCreate(savedInstanceState);
// 界面重建时,取出保留的状态
FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
if (nc != null && nc.viewModelStore != null && this.mViewModelStore == null) {
// 取出viewModelStore
this.mViewModelStore = nc.viewModelStore;
}
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable("android:support:fragments");
// 恢复fragment的状态
this.mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
....
}
}
}
public class FragmentController {
public void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
this.mHost.mFragmentManager.restoreAllState(state, nonConfig);
}
}
final class FragmentManagerImpl extends FragmentManager implements Factory2 {
void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
if (state != null) {
FragmentManagerState fms = (FragmentManagerState)state;
if (fms.mActive != null) {
List<FragmentManagerNonConfig> childNonConfigs = null;
List<ViewModelStore> viewModelStores = null;
List nonConfigFragments;
int count;
int i;
Fragment f;
if (nonConfig != null) {
nonConfigFragments = nonConfig.getFragments();
childNonConfigs = nonConfig.getChildNonConfigs();
viewModelStores = nonConfig.getViewModelStores();
count = nonConfigFragments != null ? nonConfigFragments.size() : 0;
// 遍历可保留的fragment --->fragment.setRetainInstance(true)
for(i = 0; i < count; ++i) {
// 取出fragment
f = (Fragment)nonConfigFragments.get(i);
...
int index;
// 计算当前f 对应fms.mActive位置
for(index = 0; index < fms.mActive.length && fms.mActive[index].mIndex != f.mIndex; ++index) {
;
}
...
// 取出当前fragment所保留的状态
FragmentState fs = fms.mActive[index];
// 将当前fragment保存到状态对象中,下面通过FragmentState获取fragment时直接返回
fs.mInstance = f;
...
}
}
// 初始化 mActive
this.mActive = new SparseArray(fms.mActive.length);
int i;
for(i = 0; i < fms.mActive.length; ++i) {
FragmentState fs = fms.mActive[i];
if (fs != null) {
// 取出 childFragment 保留的状态
FragmentManagerNonConfig childNonConfig = null;
if (childNonConfigs != null && i < childNonConfigs.size()) {
childNonConfig = (FragmentManagerNonConfig)childNonConfigs.get(i);
}
// 取出Fragment保留的ViewModelStore
ViewModelStore viewModelStore = null;
if (viewModelStores != null && i < viewModelStores.size()) {
viewModelStore = (ViewModelStore)viewModelStores.get(i);
}
// 构建fragment,fs存在fragment就返回,否则新建fragment实例
Fragment f = fs.instantiate(this.mHost, this.mContainer, this.mParent, childNonConfig, viewModelStore);
// 将fragment 保存到mActive中
this.mActive.put(f.mIndex, f);
fs.mInstance = null;
}
}
...
}
}
}
final class FragmentState implements Parcelable {
public Fragment instantiate(FragmentHostCallback host, FragmentContainer container, Fragment parent, FragmentManagerNonConfig childNonConfig, ViewModelStore viewModelStore) {
// 当前Fragment mInstance是否为空
// fragment.setRetainInstance(true)这种情况 mInstance不为空,会复用销毁前所保留的fragment
if (this.mInstance == null) {
Context context = host.getContext();
...
// mInstance创建新实例
if (container != null) {
this.mInstance = container.instantiate(context, this.mClassName, this.mArguments);
} else {
this.mInstance = Fragment.instantiate(context, this.mClassName, this.mArguments);
}
}
this.mInstance.mChildNonConfig = childNonConfig;
// 复用viewModelStore
this.mInstance.mViewModelStore = viewModelStore;
return this.mInstance;
}
}
到这里 fragment的ViewModelStore复用就分析完了
小结:
fragment的viewModelstore复用也是通过FragmentActivity的onRetainNonConfigurationInstance()和getLastNonConfigurationInstance()机制实现的。
界面销毁时:
在FragmentActivity.onSaveInstance()中对Fragment的相关状态mSavedNonConfig(保留了ViewModelStore等状态)进行保留,然后在onRetainNonConfigurationInstance()中取出mSavedNonConfig保存到 FragmentActivity.NonConfigurationInstances 中,
界面重建时:
在onCreat()中恢复
至此,viewModel源码分析结束
写博客的目的是为了加深印象,梳理思路,也为了方便后面复习。
文章未经仔细梳理,勉强能看…