Bootstrap

由浅入深,详解ViewModel那些事

在这里插入图片描述

前言:今年的龙舟雨来了,一场接一场,雨量很大。

前言

  以往如果需要在 Activity 或者 Fragment 中保存数据状态则需要重写onSaveInstanceState ,使用bundle去存储相应的数据和状态,但是这也只能保存轻量简单的序列化数据。而 ViewModel 可以做到在配置变更后依然持有状态。

现在的 MVVM 架构模式中,将 View数据与逻辑放在 ViewModel 中(即 MVP 中的Presenter),而 ViewModel 是不需要持有UI层引用的(因为 ViewModel 的生命周期更长),然后对外暴露观察者,一般是搭配 LiveData 一起使用,以此更容易的保持状态同步。那么就避免了可能的内存泄漏,同时实现了解耦。

一、什么是ViewModel

ViewModel 作为 JetPack 核心组件,它的实现远没有我们想象的那么简单。
ViewModel 类是一种业务逻辑或屏幕级状态容器。简单理解就是为UI层提供数据,以及封装相关的业务逻辑

它的主要优点是,它可以缓存状态,并可在配置更改后持久保留相应状态。这意味着在 Activity 之间导航时或进行配置更改后(例如旋转屏幕时),界面将无需重新请求数据。

  • 具备宿主生命周期感知能力的数据存储组件(它只能感知宿主被销毁的事件);
  • ViewModel 保存的数据,在页面因配置变更导致页面销毁重建之后依然存在的。

配置变更

配置变更是指应用内的配置参数变更从而触发的 Activity 重新创建

常见的配置变更场景:横竖屏切换、分辨率调整、权限变更、系统字体样式变更等。

生命周期

关于 ViewModel 的生命周期,具体如下图所示:

在这里插入图片描述

ViewModel 最重要的特点是 生命周期长于Activity。它只能感知宿主被销毁的事件(onDestory),可以复写 onCleared() 来做一些清理和释放的工作。(Fragment的生命周期也是同理)

这是一个Jetpack组件 + MVVM架构模式的开源实战项目,加入 组件化模块化协程Flow短视频打造一个大型的 Android 项目架构。项目地址:https://github.com/suming77/SumTea_Android

二、ViewModel的用法

先来了解一下如何使用 ViewModel。

1.常规用法

ViewModel 存储的数据,仅仅只能当页面因为配置变更导致的销毁再重建时复用。复用的是 ViewModel 的实例对象整体。

ViewModel 层请求数据,处理业务逻辑:

class MainViewModel : ViewModel() {
    val userLiveData = MutableLiveData<String>()

    fun getUserInfo() {
        //为了适配因配置变更而导致的页面重建,重复利用之前的数据,加快新页面渲染,不在请求接口
        //如果value不为空,说明这个ViewModel肯定是复用的,因为新建的ViewModel的liveData是不会有数据的
        if (userLiveData.value == null) {
            // 模拟请求接口返回数据
            viewModelScope.launch {
                delay(1000)
                userLiveData.postValue("苏火火 苏火火 苏火火 苏火火 苏火火")
            }
        }
    }
}

UI层处理显示逻辑:

class MainActivity : BaseDataBindActivity<ActivityViewmodelBinding>() {

    override fun onCreate(savedInstanceState: Bundle?) {
        LogUtil.d("onCreate()")
        //通过ViewModelProvider来获取ViewModel对象
        val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
        //注册监听,监听数据的回调
        viewModel.userLiveData.observe(this, Observer {
            //接收到数据
            dismissLoading()
            mBinding.tvUserInfo.text = it
        })

        mBinding.tvRequestUserInfo.onClick {
            // 请求数据
            showLoading()
            viewModel.getUserInfo()
        }
    }

    override fun onStop() {
        super.onStop()
        LogUtil.d("onStop()")
    }

    override fun onDestroy() {
        super.onDestroy()
        LogUtil.d("onDestroy()")
    }
}

生命周期打印数据如下:

/com.sum.tea D/LogUtil: onStop()
/com.sum.tea D/LogUtil: onDestroy()
/com.sum.tea D/LogUtil: onCreate()

2.单Activity多Fragment数据共享

Activity 中的多个 Fragment 需要相互通信是一种很常见的情况。以往通信的方式有接口,ResultAPI,EventBus,广播等多种方式,而 ViewModel 也可以实现一个 Activity 与其中的多个 Fragment 之间的相互通信

//发送数据
class UserFragment : BaseDataBindFragment<FragmentMainBinding>() {
    override fun initView(view: View, savedInstanceState: Bundle?) {
        val viewModel = ViewModelProvider(requireActivity()).get(MainViewModel::class.java)
        // 获取ViewModel,注意传入的是宿主Activity
        viewModel.userLiveData.observe(this) {
            mBinding.tvUserInfo.text = it
        }
    }
}
//接收数据
class VideoFragment : BaseDataBindFragment<FragmentMainBinding>() {
    override fun initView(view: View, savedInstanceState: Bundle?) {
        // 获取ViewModel,注意传入的是宿主Activity
        val viewModel = ViewModelProvider(requireActivity()).get(MainViewModel::class.java)
        viewModel.userLiveData.value = "我是苏火火,我是苏火火,我是苏火火"
    }
}

3.跨页面数据共享

还可以使用它跨页面跨 Activity 数据共享,只要 Application 实现 ViewModelStoreOwner 就可以了,其他页面通过 application 获取 ViewModel:

//让Application实现ViewModelStoreOwner接口
class SumApplication : Application(), ViewModelStoreOwner {

    private val appViewModelStore: ViewModelStore by lazy {
        ViewModelStore()
    }

    override fun getViewModelStore(): ViewModelStore {
        return appViewModelStore
    }
}

//其他页面通过application获取viewModel
val viewModel = ViewModelProvider(application).get(MainViewModel::class.java)

如果是正常关闭一个页面,ViewModel 的数据还是正常被关闭被清理的。有人会疑惑,页面都被销毁了,为什么数据还继续存在?实际上是 ViewModel 被保存了下来,页面被重建之后,我们在获取 ViewModel 实例的时候实际上还是同一个,从而达到里面数据的复用。

三、ViewModel的实现原理

很多人说 ViewModel 实现原理都是说成 ViewModel 是如何实现数据复用的,其实这种说法是不够准确的,因为 ViewModel 能够实现数据复用,本质上是 ViewModel 的实例对象得到了复用。准确点来说是 ViewModel 在宿主销毁了,还能继续存在。以至于页面恢复重建后,还能接着复用。(肯定是前后获取到的是同一个 ViewModel 实例对象)

先来认识 ViewModel 中几个重要的类:

  • ViewModelProvider:  提供获取 ViewModel 实例的类,ViewModel 都是从这个类中获取。
  • ViewModelStoreOwner:核心接口,该接口的实现类表示能够为外部提供 ViewModelStore 实例
  • ViewModelStore:   核心类,存储 ViewModel 实例的类,实际是一个HashMap。
  • Factory:        核心接口,负责创建 ViewModel 实例。

如果要分析 ViewModel 复用的原理,就要从如何获取 ViewModel 的实例说起。

1.ViewModel的存储和获取

获取 ViewModel 的实例过程:

val viewModel = ViewModelProvider(activity).get(HiViewModel::class.java)

ViewModelProvider 类有三个构造函数,无论你使用的是哪个构造函数,最后都会调用ViewModelProvider(ViewModelStore store, Factory factory)

#ViewModelProvider.java
public ViewModelProvider(ViewModelStoreOwner owner) {
    this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
            ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
            : NewInstanceFactory.getInstance());
}

public ViewModelProvider(ViewModelStoreOwner owner, Factory factory) {
    this(owner.getViewModelStore(), factory);
}

public ViewModelProvider(ViewModelStore store, Factory factory) {
    mFactory = factory;
    mViewModelStore = store;
}

在创建 ViewModelProvider 的时候,参数虽然是 Activity,实际上这里要求的是 ViewModelStoreOwner,那是因为 Activity 也就是 ComponentActivity 它实现了 ViewModelStoreOwner 这个接口的,并且复写了 getViewModelStore() 方法,然后把 Store 和 Factory 两个参数保存了起来:

public interface ViewModelStoreOwner {
    //获取ViewModelStore
    ViewModelStore getViewModelStore();
}

这个 ViewModelStore 就是用来存储 ViewModel 实例的,它本质上就是一个 HashMap,非常简单:

//用于存储ViewModel实例
public class ViewModelStore {

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    // 保存viewModel实例
    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);
    }

    Set<String> keys() {
        return new HashSet<>(mMap.keySet());
    }

    //清除ViewModel
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

如果不传递 Factory 参数则会有个默认的,Factory 就是用来创建 ViewModel 实例的,当我们从 ViewModelStore 里面获取 ViewModel 实例的时候,如果获取不到,就会通过 Factory 来创建它,待会来分析它,继续看 ViewModelProvider 的 get 方法:

#ViewModelProvider.java
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
    String canonicalName = modelClass.getCanonicalName();
    //拿到Key,即ViewModelStore中的Map用于存ViewModel的Key
    return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}

private static final String DEFAULT_KEY =
        "androidx.lifecycle.ViewModelProvider.DefaultKey";

通过 canonicalName 和 DEFAULT_KEY 字段拼接成一个字符串,从而形成一个完整的 Key 字段,就是在 ViewModelStore 里面存储 ViewModel 的 key

#ViewModelProvider.java
@MainThread
public <T extends ViewModel> T get(String key, Class<T> modelClass) {
    //根据key从ViewModelStore中获取ViewModel实例
    ViewModel viewModel = mViewModelStore.get(key);

    if (modelClass.isInstance(viewModel)) {
        if (mFactory instanceof OnRequeryFactory) {
            ((OnRequeryFactory) mFactory).onRequery(viewModel);
        }
        // 如果有这个实例则返回
        return (T) viewModel;
    } 
    
    // 根据mFactory的类型来创建ViewModel实例
    if (mFactory instanceof KeyedFactory) {
        viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
    } else {
        viewModel = mFactory.create(modelClass);
    }
    // 存储到ViewModelStore中
    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}

回到第一个构造函数中:

ViewModelProviderpublic ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
    this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
            ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
            : NewInstanceFactory.getInstance());
}

getDefaultViewModelProviderFactory() 实际是 SavedStateViewModelFactory:

SavedStateViewModelFactory类:
@Override
public <T extends ViewModel> T create(String key, Class<T> modelClass) {
    // 判断是否为AndroidViewModel
    boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
    Constructor<T> constructor;
    // 获取构造器
    if (isAndroidViewModel && mApplication != null) {
        constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
    } else {
        constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
    }
    // 普通方式创建ViewModel实例
    if (constructor == null) {
        return mFactory.create(modelClass);
    }

    try {
        T viewmodel;
        if (isAndroidViewModel && mApplication != null) {
            viewmodel = constructor.newInstance(mApplication, controller.getHandle());
        } else {
            viewmodel = constructor.newInstance(controller.getHandle());
        }
        return viewmodel;
}

创建的时候判断 modelClass 是否拥有两种构造函数:

//第一种:有两个参数
private static final Class<?>[] ANDROID_VIEWMODEL_SIGNATURE = new Class[]{Application.class,
        SavedStateHandle.class};
//第二种:只有一个参数
private static final Class<?>[] VIEWMODEL_SIGNATURE = new Class[]{SavedStateHandle.class};

如果上面两种都没有,那个在构造实例的时候,就会以普通的形式构造实例 AndroidViewModelFactory,实际上是通过反射

  if (constructor == null) {
        return mFactory.create(modelClass);
    }

而 NewInstanceFactory 则是一个简单的创建工厂,根据空构造函数,直接通过 Class 直接创建一个 ViewModel 实例

public static class NewInstanceFactory implements Factory {
    @Override
    public <T extends ViewModel> T create(@Class<T> modelClass) {
         // 通过modelClass反射获取ViewModel实例
         return modelClass.newInstance();
    }
}

首先通过 mViewModelStore 根据 key 获取 ViewModel 实例,还会判断该实例是不是传入的 Class 类型的,如果是则直接返回,如果不是则会根据 mFactory 是什么类型的,来决定是用什么创建方式来创建 ViewModel 实例,创建完成后存储到 ViewModelStore 中。这就是 ViewModel 实例的存储和获取过程。

2.ViewModelStore的存储和获取

ViewModel 实例是用 ViewModelStore 来获取的,既然要做到 ViewModel 实例的复用,那么 ViewModelStore 它也必须做到复用才可以,关键点就在这里,ViewModelStore 是在 ComponentActivity 里面被获取的:

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory {
        
    public ViewModelStore getViewModelStore() {
        // 如果存储器为空则从NonConfigurationInstances中获取
        if (mViewModelStore == null) {
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                //从NonConfigurationInstances中恢复ViewModelStore
                mViewModelStore = nc.viewModelStore;
            }
            // 如果获取不到,则直接创建一个
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }
}

注意了,首先通过 NonConfigurationInstances 获取 ViewModelStore,如果 NonConfigurationInstances 不存则创建一个 ViewModelStore 实例。那么 NonConfigurationInstances 是什么?

static final class NonConfigurationInstances {
    Object custom;
    ViewModelStore viewModelStore;
}

NonConfigurationInstance s对象本质上是一个包装类,包装一些在配置变更后还想留存的数据,比如说 Fragment,如果一个 Activity 上面有一个 Fragment,我们的页面在旋转了以后,Activity 会被重建,Fragment 还是原来的哪一个,这里的实现原理就是通过 NonConfigurationInstances 来实现的,那么 ViewModel 的复用也是同样的原理。

但是 ViewModel 对象的存储发生在什么时候呢?要先存储了才能够实现复用,实际发生在 onRetainNonConfigurationInstance() 方法里面:

#ComponentActivity.java
@Override
// 在Activity因配置变更而销毁再重建Activity时,此方法会被调用
// 因配置变更而被销毁而保存的数据,在重建的时候还想继续复用
public final Object onRetainNonConfigurationInstance() {
    Object custom = onRetainCustomNonConfigurationInstance();

    ViewModelStore viewModelStore = mViewModelStore;
    if (viewModelStore == null) {
        // 尝试从NonConfigurationInstance获取ViewModelStore
        NonConfigurationInstances nc =
        (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            viewModelStore = nc.viewModelStore;
        }
    }

    // 如果 viewModelStore == null 则直接返回null
    if (viewModelStore == null && custom == null) {
        return null;
    }

    // viewModelStore不为空则构建了一个NonConfigurationInstances对象,并且把viewModelStore存了进去。
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom;
    nci.viewModelStore = viewModelStore;
    return nci;
}

重点来了,在 Activity 因配置变更而要销毁时,且会重新创建 Activity,系统就会调用这个方法。 也就说,配置改变时系统把 viewModelStore 存在了 NonConfigurationInstances 中

跟进 onRetainNonConfigurationInstance(),它是复写父类的,在 Activity 里面找到调用它的时机:

#Activity.java
NonConfigurationInstances retainNonConfigurationInstances() {
    Object activity = onRetainNonConfigurationInstance();
    HashMap<String, Object> children = onRetainNonConfigurationChildInstances();

    //······
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.activity = activity;
    nci.children = children;
    nci.fragments = fragments;
    nci.loaders = loaders;
    if (mVoiceInteractor != null) {
        mVoiceInteractor.retainInstance();
        nci.voiceInteractor = mVoiceInteractor;
    }
    return nci;
}

重要的是retainNonConfigurationInstances()这个方法的调用入口在哪里呢?这个是无法在IDE中查看的,它实际是在 ActivityThread 里面。

3.Activity的重建流程

正常启动一个 Activity 的时候,它会在执行 ActivityThread 的 handleLaunchActivity(),但是一个页面因为配置变更而重建的时候它执行 handleRelaunchActivity() 方法,这个方法是重新创建 Avtivity 的一个入口,但是它正在创建的方法是在里面的 handleRelaunchActivityInner

#ActivityThread.java
//因为配置变更而重建的时候会执行
@Override
public void handleRelaunchActivity(ActivityClientRecord tmp,
        PendingTransactionActions pendingActions) {
    //·····
    //mActivities里面存储的就是当前应用当前进程所已经打开的所有Activity信息的集合
    ActivityClientRecord r = mActivities.get(tmp.token);

    // 重新创建Activity执行
    handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents,
        pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity");
     //·····
}

mActivities 里面存储的就是当前应用当前进程所已经打开的所有 Activity 信息的集合,通过 mActivities 集合获取到一个
ActivityClientRecord,它里面有个重要的参数lastNonConfigurationInstances

public static final class ActivityClientRecord {
    //······
    //因配置变更而被销毁的Activity它所存留下来的数据
    Activity.NonConfigurationInstances lastNonConfigurationInstances;
}

它所存储的就是因配置变更而被销毁的 Activity 它所存留下来的配置,只不过在这个方法当中它的值还是空的。

// 执行重新创建Activity
private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,
        List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents,
        PendingTransactionActions pendingActions, boolean startsNotResumed,
        Configuration overrideConfig, String reason) {
    //保留上次使用的Intent
    final Intent customIntent = r.activity.mIntent;
    //重新创建Acitivty之前需要把发生配置变更的Activity销毁掉
    if (!r.paused) {
        performPauseActivity(r, false, reason, null /* pendingActions */);
    }
    if (!r.stopped) {
        callActivityOnStop(r, true /* saveState */, reason);
    }

    // 销毁Activity
    handleDestroyActivity(r, false, configChanges, true, reason);

    //创建和启动Activity
    handleLaunchActivity(r, pendingActions, customIntent);
}

在重新创建 Acitivty 之前需要把发生配置变更的 Activity 销毁掉,所以执行配置变更的 performPauseActivity() 方法以及 callActivityOnStop() 方法,在 callActivityOnStop() 一并执行 callActivityOnSaveInstanceState(r) 并且有机会存储数据。

@Override
public void handleDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges,
        boolean getNonConfigInstance, String reason) {
    // 执行Activity销毁方法的核心方法
    performDestroyActivity(r, finishing, configChanges, getNonConfigInstance, reason);
}

handleDestroyActivity() 方法里面有个 boolean getNonConfigInstance 参数, performDestroyActivity() 是执行 Activity 销毁方法的核心方法

// 销毁Activity
void performDestroyActivity(ActivityClientRecord r, boolean finishing,
        int configChanges, boolean getNonConfigInstance, String reason) {
    activityClass = r.activity.getClass();
    //·····
    if (!r.stopped) {
        callActivityOnStop(r, false /* saveState */, "destroy");
    }
    // 保存lastNonConfigurationInstances,从而保存了数据
    if (getNonConfigInstance) {
       r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
    }
}

如果 getNonConfigInstance == true,则会执行 r.activity.retainNonConfigurationInstances() 方法,从而把 Activity 当中受到配置变更而不想丢失的数据给保存起来,这样 ViewModelStore 对象也就被保存起来了。数据就被存储在 lastNonConfigurationInstances 里面:

image.png

这个数据都会被保存到 ActivityClientRecord 的 lastNonConfigurationInstances 里面,这个r对象是通过 ActivityClientRecord r = mActivities.get(tmp.token) 获取的,那实际上就跟在 handleLaunchActivity() 当中获取到的那个 ActivityClientRecord 对象是同一个实例对象。

那么在 performDestroyActivity() 中的 ActivityClientRecord 就包含了被销毁的 Activity 存留下来的对象,销毁之后就执行 Avtivity 重建工作,重建最终会走到 performLaunchActivity() 方法,执行 newActivity() 去 New 一个 Activity,还会执行 activity.attach() 方法:

// 执行创建启动Activity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ActivityInfo aInfo = r.activityInfo;

    //······
    Activity activity = null;
    // 创建Activity
    activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);

    //里面保存了lastNonConfigurationInstances,省略部分参数
     activity.attach(appContext, this, r.lastNonConfigurationInstances ····);

            r.lastNonConfigurationInstances = null;
            
            r.activity = activity;
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
        }
        r.setState(ON_CREATE);
    }

    return activity;
}

这里又把 r.lastNonConfigurationInstances 传递了进去,在 Activity 类中的 attach() 方法就把 lastNonConfigurationInstances 保存起来:

#Activity.java
final void attach(Context context, ActivityThread aThread,
        NonConfigurationInstances lastNonConfigurationInstances ······) {
    // 保存lastNonConfigurationInstances
    mLastNonConfigurationInstances = lastNonConfigurationInstances;
}

所以我们在 CompontentActivity 当中的 getLastNonConfigurationInstance() 中的 mLastNonConfigurationInstances 获取到数据了:

@Nullable
public Object getLastNonConfigurationInstance() {
    return mLastNonConfigurationInstances != null
            ? mLastNonConfigurationInstances.activity : null;
}

那么就可以在 getViewModelStore() 中获取到 NonConfigurationInstances 从而完成 viewModelStore 对象的复用。

@Override
public ViewModelStore getViewModelStore() {
    // 如果存储器为空则从NonConfigurationInstances中获取
    if (mViewModelStore == null) {
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            //从NonConfigurationInstances中恢复ViewModelStore
            mViewModelStore = nc.viewModelStore;
        }
        // 如果还为空则创建一个ViewModelStore
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
        }
    }
    return mViewModelStore;
}

也就是说,ActivityThread 中的 ActivityClientRecord 是不受 Activity 销毁重建的影响而被保存下来,ActivityClientRecord中的lastNonConfigurationInstances也就被保存下来,那么ComponentActivity中的NonConfigurationInstances的viewModelStore就被保存下来实现复用。

到这里 ViewModel 复用的分析完了,本质上就是 ViewModelStore 的复用,顺便分析了一把 Activity 销毁重建的流程。

四、总结

ViewModel 的执行流程如下:

在这里插入图片描述

  1. ViewModelProvider 从 ViewModelStore 根据 key 获取 ViewModel实例,判断该实例的 Class 类型的,如果是则直接返回,如果不是则会根据 mFactory 是什么类型的,来决定是用什么创建方式来创建 ViewModel 实例,创建完成后存储到 ViewModelStore 中

  2. Activity 实现了 ViewModelStoreOwner 这个接口,并复写了 getViewModelStore() 方法,先从 NonConfigurationInstances 里面获取 ViewModelStore,如果没有就创建新的实例并保存起来

  3. ViewModelStore 通过 key-value 的形式存储 ViewModel,而它自己在 Activity 因配置变更而销毁再重建时,调用 onRetainNonConfigurationInstance() 存储在 NonConfigurationInstances 里面

  4. Activity 销毁时会将 NonConfigurationInstances 保存在ActivityThread#ActivityClientRecord 中,重建后通 Activity.attach() 重新传递给Activity,实现复用

  5. ActivityThread 中的 ActivityClientRecord 是不受 Activity 销毁重建的影响而被保存下来,ActivityClientRecord中的lastNonConfigurationInstances也就被保存下来,那么ComponentActivity中的NonConfigurationInstances的viewModelStore就被保存下来实现复用

因为 ViewModel 能够实现数据复用,本质上是 ViewModel 的实例对象得到了复用。

源码地址:https://github.com/suming77/SumTea_Android

点关注,不迷路


好了各位,以上就是这篇文章的全部内容了,很感谢您阅读这篇文章。我是suming,感谢各位的支持和认可,您的点赞就是我创作的最大动力。山水有相逢,我们下篇文章见!

本人水平有限,文章难免会有错误,请批评指正,不胜感激 !

参考链接:

希望我们能成为朋友,在 Github博客 上一起分享知识,一起共勉!Keep Moving!

;