iewModel 是 Android 架构组件之一,用于分离 UI 逻辑与 UI 数据。在发生 Configuration Changes 时,它不会被销毁。在界面重建后,方便开发者呈现界面销毁前的 UI 状态。
本文主要分析 ViewModel 的以下3个方面:
1. 获取和创建过程。
2. Configuration Changes 存活原理。
3. 销毁过程。
implementation"androidx.fragment:fragment:1.0.0" implementation"androidx.lifecycle:lifecycle-viewmodel:2.0.0" implementation"androidx.lifecycle:lifecycle-extensions:2.0.0"
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;
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; } }
获取 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; }
当 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()。
在 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(); }
以上便是 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
→我们致力于为广大网民解决所遇到的各种电脑技术问题 如果您认为本词条还有待完善,请 编辑词条