词条信息

admin
admin
超级管理员
最近编辑者 发短消息   

相关词条

热门词条

更多>>
一个宽带装两个路由器怎么设置?
很多朋友可能存这种情况,家里房间比较多,之前已经安装了一个无线路由器,但是在某些房间信号很差,想再增加一个...
宽带升级到200兆了,路由器和网线是不是需要更换?
事实上,200兆宽带需要支持千兆网络传输速率的硬件。尽管200兆与千兆相差很大,但目前网络传输速率只有百兆和千...
2019年电子商务发展4大主流趋势
随着在线零售业的竞争日趋激烈,企业和卖家只有积极利用科技趋势才能保住增长势头,立于不败之地。据市场研究公司 S...
超1亿人朋友圈“仅三天可见”
你有多少个真正称得上朋友的人?前段时间微信创始人、腾讯公司高级副总裁张小龙在年度演讲里说起关于朋友圈的一件事:...
半夜总是醒了又睡睡了又醒怎么办?
现在是一个全民缺觉的时代,越来越多人因为加班、情感、焦虑等问题困扰着自己的失眠。急剧下降的睡眠质量,同样也会影...
解决网 >>所属分类 >> 架构   

剖析 Android 架构组件之 ViewModel

标签: Android 架构组件 ViewModel

顶[0] 发表评论(0) 编辑词条

iewModel 是 Android 架构组件之一,用于分离 UI 逻辑与 UI 数据。在发生 Configuration Changes 时,它不会被销毁。在界面重建后,方便开发者呈现界面销毁前的 UI 状态。


本文主要分析 ViewModel 的以下3个方面:


  1. 获取和创建过程。

  2. Configuration Changes 存活原理。

  3. 销毁过程。


目录

1. 依赖库编辑本段回目录


implementation"androidx.fragment:fragment:1.0.0"

implementation"androidx.lifecycle:lifecycle-viewmodel:2.0.0"

implementation"androidx.lifecycle:lifecycle-extensions:2.0.0"


2. 主要类与接口编辑本段回目录


importandroidx.fragment.app.Fragment;

importandroidx.fragment.app.FragmentActivity;

importandroidx.lifecycle.ViewModel;

importandroidx.lifecycle.AndroidViewModel;

importandroidx.lifecycle.ViewModelProvider;

importandroidx.lifecycle.ViewModelProvider.Factory;

importandroidx.lifecycle.ViewModelProviders;

importandroidx.lifecycle.ViewModelStore;

importandroidx.lifecycle.ViewModelStoreOwner;


3. ViewModel编辑本段回目录


ViewModel 是一个抽象类,类中只定义了一个空实现的 onCleared() 方法。


publicabstractclassViewModel{

/**

* This method will be called when this ViewModel is no longer used and will be destroyed.

* <p>

* It is useful when ViewModel observes some data and you need to clear this subion to

* prevent a leak of this ViewModel.

*/

@SuppressWarnings("WeakerAccess")

protectedvoidonCleared() {

}

}


3.1 AndroidViewModel


AndroidViewModel 类扩展了 ViewModel 类,增加了 Application 字段,在构造方法初始化,并提供了 getApplication() 方法。


publicclassAndroidViewModelextendsViewModel{

privateApplication mApplication;

publicAndroidViewModel(@NonNull Application application){

mApplication = application;

}

/**

* Return the application.

*/

@NonNull

public<T extends Application> T getApplication(){

return(T) mApplication;

}
}


4. 获取和创建过程分析编辑本段回目录

获取 ViewModel 对象代码如下:


ViewModelProviders.of(activityOrFragment).get(ViewModel::class.java)


4.1 ViewModelProviders


ViewModelProviders 类提供了4个静态工厂方法 of() 创建新的 ViewModelProvider 对象。


ViewModelProviders.of(Fragment)



ViewModelProviders.of(FragmentActivity)



ViewModelProviders.of(Fragment, Factory)



ViewModelProviders.of(FragmentActivity, Factory)


4.2 ViewModelProvider


ViewModelProvider 负责提供 ViewModel 对象,类中定义了以下两个字段:


privatefinalFactory mFactory;

privatefinalViewModelStore mViewModelStore;


先说说这两个类的功能。


4.3 ViewModelProvider.Factory


Factory 接口定义了一个创建 ViewModel 的接口 create(),ViewModelProvider 在需要时调用该方法新建 ViewModel 对象。


publicinterfaceFactory{

<T extends ViewModel> T create(@NonNull Class<T> modelClass);

}


Android 已经内置了2个 Factory 实现类,分别是:


AndroidViewModelFactory 实现类,可以创建 ViewModel 和 AndroidViewModel 子类对象。


NewInstanceFactory 类,只可以创建 ViewModel 子类对象。


它们的实现都是通过反射机制调用 ViewModel 子类的构造方法创建对象。


publicstaticclassNewInstanceFactoryimplementsFactory{

@Override

public<T extends ViewModel> T create(Class<T> modelClass){

try{

returnmodelClass.newInstance();

} catch(InstantiationException e) {

thrownewRuntimeException("Cannot create an instance of "+ modelClass, e);

} catch(IllegalAccessException e) {

thrownewRuntimeException("Cannot create an instance of "+ modelClass, e);

}

}

}


AndroidViewModelFactory 继承 NewInstanceFactory 类,是个单例,支持创建 AndroidViewModel 子类对象。


publicstaticclassAndroidViewModelFactoryextendsViewModelProvider.NewInstanceFactory{

privatestaticAndroidViewModelFactory sInstance;

publicstaticAndroidViewModelFactory getInstance(Application application){

if(sInstance == null) {

sInstance = newAndroidViewModelFactory(application);

}

returnsInstance;

}

privateApplication mApplication;

publicAndroidViewModelFactory(Application application){

mApplication = application;

}

@Override

public<T extends ViewModel> T create(Class<T> modelClass){

if(AndroidViewModel.class.isAssignableFrom(modelClass)) {

try{

returnmodelClass.getConstructor(Application.class).newInstance(mApplication);

} catch(NoSuchMethodException e) {

thrownewRuntimeException("Cannot create an instance of "+ modelClass, e);

} catch(IllegalAccessException e) {

thrownewRuntimeException("Cannot create an instance of "+ modelClass, e);

} catch(InstantiationException e) {

thrownewRuntimeException("Cannot create an instance of "+ modelClass, e);

} catch(InvocationTargetException e) {

thrownewRuntimeException("Cannot create an instance of "+ modelClass, e);

}

}

returnsuper.create(modelClass);

}

}


4.4 ViewModelStore


ViewModelStore 类中维护一个 Map 对象存储已创建的 ViewModel 对象,并提供 put() 和 get() 方法。


public classViewModelStore{

private finalHashMap<String, ViewModel> mMap = newHashMap<>();

finalvoidput(Stringkey, ViewModel viewModel) {

ViewModel oldViewModel = mMap.put(key, viewModel);

}

finalViewModel get(Stringkey) {

returnmMap.get(key);

}

}


4.5 ViewModelStoreOwner


ViewModelStore 是来自于 FragmentActivity 和 Fragment,它们实现了 ViewModelStoreOwner 接口,返回当前 UI 作用域里的 ViewModelStore 对象。


publicinterfaceViewModelStoreOwner{

ViewModelStore getViewModelStore();

}


在 Fragment 类中的实现如下:


publicViewModelStore getViewModelStore() {

if(getContext() == null) {

thrownewIllegalStateException("Can't access ViewModels from detached fragment");

}

if(mViewModelStore == null) {

mViewModelStore = newViewModelStore();

}

returnmViewModelStore;

}


在 FragmentActivity 类中的实现如下:


publicViewModelStore getViewModelStore() {

if(getApplication() == null) {

thrownewIllegalStateException("Your activity is not yet attached to the "

+ "Application instance. You can't request ViewModel before onCreate call.");

}

if(mViewModelStore == null) {

mViewModelStore = newViewModelStore();

}

returnmViewModelStore;

}


4.6 创建 ViewModelProvider


回到 of() 方法的实现


public staticViewModelProvider of(FragmentActivity activity, Factory factory) {

Application application = checkApplication(activity);

if(factory== null) {

factory= ViewModelProvider.AndroidViewModelFactory.getInstance(application);

}

returnnewViewModelProvider(activity.getViewModelStore(), factory);

}


在创建 ViewModelProvider 对象时需要传入 ViewModelStore 和 Factory 对象。若 factory 为 null,将使用 AndroidViewModelFactory 单例对象。


4.7 获取 ViewModel 对象


调用 ViewModelProvider 对象的 get() 方法获取 ViewModel 对象,如果在 ViewModelStore 里不存在,则使用 Factory 创建一个新的对象并存放到 ViewModelStore 里。


public <Textends ViewModel> Tget(String key, 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;

}

5. Configuration Changes 存活原理编辑本段回目录


当 Activity 或 Fragment 被系统重建时,ViewModel 对象不会被销毁,新的 Activity 或 Fragment 对象拿到的是同一个 ViewModel 对象。


在 FragmentActivity#onRetainNonConfigurationInstance() 方法中,会将 ViewModelStore 对象保留起来。


publicfinalObject onRetainNonConfigurationInstance(){

Object custom = onRetainCustomNonConfigurationInstance();

FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();

if(fragments == null&& mViewModelStore == null&& custom == null) {

returnnull;

}

NonConfigurationInstances nci = newNonConfigurationInstances();

nci.custom = custom;

nci.viewModelStore = mViewModelStore;

nci.fragments = fragments;

returnnci;

}


然后在 onCreate() 方法能获取之前保留起来的 ViewModelStore 对象。


protectedvoidonCreate(Bundle savedInstanceState){

mFragments.attachHost(null/*parent*/);

super.onCreate(savedInstanceState);

NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();

if(nc != null) {

mViewModelStore = nc.viewModelStore;

}

// ...

}


那 Fragment 作用域里是如何实现的呢?在 FragmentActivity 的 onRetainNonConfigurationInstance() 方法中里有这样一句代码:


FragmentManagerNonConfigfragments = mFragments.retainNestedNonConfig();


实现保留的机制是一样的,只不过放在 FragmentManagerNonConfig 对象中。是在 FragmentManager#saveNonConfig() 方法中将 ViewModelStore 对象保存到 FragmentManagerNonConfig 里的。


voidsaveNonConfig() {
ArrayList<Fragment> fragments = null;
ArrayList<FragmentManagerNonConfig> childFragments = null;
ArrayList<ViewModelStore> viewModelStores = null;
if(mActive != null) {
for(inti=0; i<mActive.size(); i++) {
Fragment f = mActive.valueAt(i);
if(f != null) {
if(f.mRetainInstance) {
if(fragments == null) {
fragments = newArrayList<Fragment>();
}
fragments.add(f);
f.mTargetIndex = f.mTarget != null? f.mTarget.mIndex : -1;
if(DEBUG) Log.v(TAG, "retainNonConfig: keeping retained "+ f);
}
FragmentManagerNonConfig child;
if(f.mChildFragmentManager != null) {
f.mChildFragmentManager.saveNonConfig();
child = f.mChildFragmentManager.mSavedNonConfig;
} else{
// f.mChildNonConfig may be not null, when the parent fragment is
// in the backstack.
child = f.mChildNonConfig;
}
if(childFragments == null&& child != null) {
childFragments = newArrayList<>(mActive.size());
for(intj = 0; j < i; j++) {
childFragments.add(null);
}
}
if(childFragments != null) {
childFragments.add(child);
}
if(viewModelStores == null&& f.mViewModelStore != null) {
viewModelStores = newArrayList<>(mActive.size());
for(intj = 0; j < i; j++) {
viewModelStores.add(null);
}
}
if(viewModelStores != null) {
viewModelStores.add(f.mViewModelStore);
}
}
}
}
if(fragments == null&& childFragments == null&& viewModelStores == null) {
mSavedNonConfig = null;
} else{
mSavedNonConfig = newFragmentManagerNonConfig(fragments, childFragments,
viewModelStores);
}
}

该方法的调用顺序是:FragmentActivity#onSaveInstanceState() -> FragmentManager#saveAllState() -> FragmentManager#saveNonConfig()。


6. 销毁过程编辑本段回目录


在 FragmentActivity 类的 onDestory() 方法中。


@Override
protectedvoidonDestroy(){
super.onDestroy();
if(mViewModelStore != null&& !isChangingConfigurations()) {
mViewModelStore.clear();
}
mFragments.dispatchDestroy();
}
在 Fragment 类的 onDestory() 方法中。
publicvoidonDestroy(){
mCalled = true;
FragmentActivity activity = getActivity();
booleanisChangingConfigurations = activity != null&& activity.isChangingConfigurations();
if(mViewModelStore != null&& !isChangingConfigurations) {
mViewModelStore.clear();
}
}

先判断是否有发生 Configuration Changes,如果没有则会调用 ViewModelStore 的 clear() 方法,再一一调用每一个 ViewModel 的 onCleared() 方法。


publicfinalvoidclear(){

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

vm.onCleared();

}

mMap.clear();

}


7. 总结编辑本段回目录


以上便是 ViewModel 3个主要过程的剖析,这里做一下总结。


通过 ViewModelProviders 创建 ViewModelProvider 对象,调用该对象的 get() 方法获取 ViewModel 对象。 当 ViewModelStore 里不存在想要的对象,ViewModelProvider 会使用 Factory 新建一个对象并存放到 ViewModelStore 里。


当发生 发生 Configuration Changes 时,FragmentActivity 利用 getLastNonConfigurationInstance()、onRetainNonConfigurationInstance() 方法实现 ViewModelStore 的保留与恢复,进而实现 ViewModel 对象的保活。


当 FragmentActivity 和 Fragment 被销毁时,会根据是否发生 Configuration Changes 来决定是否销毁 ViewModel。


作者:吴下阿吉

 

 

附件列表


按字母顺序浏览:A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

→我们致力于为广大网民解决所遇到的各种电脑技术问题
 如果您认为本词条还有待完善,请 编辑词条

上一篇Java 虚拟机 ( JVM ) 概述
下一篇深入理解Java中的volatile关键字

0
1. 本站部分内容来自互联网,如有任何版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
2. 本站内容仅供参考,如果您需要解决具体问题,建议您咨询相关领域专业人士。
3. 如果您没有找到需要的百科词条,您可以到百科问答提问或创建词条,等待高手解答。

关于本词条的提问

查看全部/我要提问>>