Android销毁控件对象,剖析 Android 架构组件之 ViewModel

原标题:剖析 Android 架构组件之 ViewModel

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

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

获取和创建过程。

Configuration Changes 存活原理。

销毁过程。

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.

*

* 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 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 create(@NonNull Class modelClass);

}

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

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

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

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

publicstaticclassNewInstanceFactoryimplementsFactory{

@Override

public T create(Class 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 create(Class 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 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 Tget(String key, Class 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 fragments = null;

ArrayList childFragments = null;

ArrayList viewModelStores = null;

if(mActive != null) {

for(inti=0; i

Fragment f = mActive.valueAt(i);

if(f != null) {

if(f.mRetainInstance) {

if(fragments == null) {

fragments = newArrayList();

}

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。

作者:吴下阿吉

链接:https://juejin.im/post/5beccf0a5188251e1f50c574

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Jetpack是Google提供的一套用于加速Android应用开发的工具包,其中包括了许多架构组件,其中之一就是ViewModelViewModel是一种设计模式,用于保存和管理与UI相关的数据。在传统的Android开发中,当屏幕旋转或者因为其他原因导致Activity或Fragment重建时,之前保存的临时数据就会丢失。而ViewModel的出现解决了这个问题。 ViewModel的主要作用是将数据与UI组件分离。它的工作方式是创建一个ViewModel类,并在其中保存需要与UI组件交互的数据。这样,当屏幕旋转或重建时,ViewModel实例不会销毁,数据也会得到保留。然后,在Activity或Fragment中,通过获取ViewModel实例,可以轻松地访问这些数据。 使用ViewModel的好处有很多。首先,它可以避免内存泄漏,因为ViewModel的生命周期与Activity或Fragment无关。其次,它可以节省资源,因为当Activity或Fragment销毁时,ViewModel实例可以被系统缓存起来,下次再创建时可以直接返回该实例。另外,由于ViewModel保存了与UI相关的数据,可以减少因为屏幕旋转导致的数据重复加载的问题。 在使用ViewModel时,你可以选择使用Android Jetpack中的其他架构组件来进一步提高开发效率,比如通过LiveData实现数据的观察和通知,或者通过DataBinding来实现UI与数据的自动绑定。 总之,ViewModelAndroid Jetpack中非常重要的一个架构组件,它的出现实现了数据与UI的解耦,提高了开发效率,并且解决了数据丢失的问题。希望通过这篇文档的详解,你对ViewModel有了更深入的理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值