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

前语

  以往假如需求在Activity或者Fragment中保存数据状况则需求重写onSaveInstanceState ,运用bundle去存储相应的数据和状况,可是这也只能保存轻量简略的序列化数据。而 ViewModel能够做到在装备改变后仍然持有状况。

现在的 MVVM 架构模式中,将View数据与逻辑放在ViewModel中(即 MVP 中的Presenter),而 ViewModel 是不需求持有UI层引证的(由于 ViewModel 的生命周期更长),然后对外暴露观察者,一般是搭配LiveData一同运用,以此更简单的保持状况同步。那么就避免了或许的内存走漏,同时完结了解耦。

一、什么是ViewModel

ViewModel作为JetPack中心组件,它的完结远没有咱们幻想的那么简略。 ViewModel类是一种事务逻辑或屏幕级状况容器。简略理解便是为UI层供给数据,以及封装相关的事务逻辑

它的首要长处是,它能够缓存状况,并可在装备更改后持久保留相应状况。这意味着在 Activity 之间导航时或进行装备更改后(例如旋转屏幕时),界面将无需从头恳求数据。

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

装备改变

装备改变是指使用内的装备参数改变然后触发的 Activity 从头创立

常见的装备改变场景:反正屏切换、分辨率调整、权限改变、体系字体款式改变等。

生命周期

关于ViewModel的生命周期,详细如下图所示:

由浅入深,ViewModel详解

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

二、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()

由浅入深,ViewModel详解

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?.tvTitle?.text = "UserFragment \n\n $it"
        }
    }
}
//发送数据
class VideoFragment : BaseDataBindFragment<FragmentMainBinding>() {
    override fun initView(view: View, savedInstanceState: Bundle?) {
        // 获取ViewModel,留意传入的是宿主Activity
        val viewModel = ViewModelProvider(requireActivity()).get(MainViewModel::class.java)
        viewModel.shareLiveData.value = "数据共享:VideoFragment中的数据"
    }
}

由浅入深,ViewModel详解

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)

源码地址:github.com/suming77/Su…

假如是正常关闭一个页面,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 里边:

由浅入深,ViewModel详解

这个数据都会被保存到 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 获取到数据了:

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 的履行流程如下:

由浅入深,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 的实例目标得到了复用。

ViewModel 和 onSaveIntanceState 有什么区别:

  1. onSaveIntanceState 只能存储轻量级的 key-value 键值对数据,非装备改变导致的页面收回时才触发,此刻数据存储在 ActivityRecord 中。
  2. ViewModel 能够放恣意数据,因装备改变导致的页面被收回才有用,此刻存在 ActivityThread#ActivityClientRecord 中。

可是假如由于内存缺乏,电量缺乏等体系原因导致的页面被收回重建后 ViewModel 还能不能被复用呢?答案是能够的,下篇文章讲解。

一个大型的 Android 项目架构最佳实践,根据Jetpack组件 + MVVM架构模式,加入 组件化模块化协程Flow短视频。项目地址:github.com/suming77/Su…

点重视,不走失


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

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

参阅链接:

  • ViewModel官网

期望咱们能成为朋友,在 Github、 上一同分享常识,一同共勉!Keep Moving!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。