ViewModel使用方法、原理分析(二)

170 阅读4分钟

Jetpack系列:
写文章 - Lifecycle使用方法、原理分析 - 掘金 (juejin.cn)
LiveData使用方法、原理分析 - 掘金 (juejin.cn)
ViewModel使用方法、原理分析(一) - 掘金 (juejin.cn)
ViewModel使用方法、原理分析(二) - 掘金 (juejin.cn)
自定义View中获取ViewModel - 掘金 (juejin.cn)

本章节重点分析ViewModelActivity配置发生变化时保存数据,在Android官方文档中解释ViewModel生命周期长于Activity

ViewModel 的生命周期

ViewModel对象的作用域限定为获取 ViewModel时传递给ViewModelProvider的 ViewModelStoreOwnerLifecycle将一直留在内存中,直到其作用域ViewModelStoreOwner永久消失,ViewModels 成为了存储在配置更改后仍然存在的数据的绝佳解决方案

image.png

PS: activity 经历屏幕旋转而后结束时所处的各种生命周期状态,代码验证一下

class CustomViewModel(savedStateHandle: SavedStateHandle):ViewModel() {
    var count = 1
    init {
        val param = savedStateHandle.get<String>("param")
        Log.d("TAG", "===========param:$param")    
        count = 100
    }
     fun changeValue(){
        count = 100
    }
}

class CustomViewActivity:ComponentActivity() {
    private val viewModel by viewModels<CustomViewModel>()

    override fun onResume() {
        super.onResume()
        Log.d("TAG", "===========count:${viewModel.count}")
        viewModel.changeValue()
    }
}
=========onCreate========
=========onStart========
=========onResume========
===========viewModel:com.malaysia.myapplication.CustomViewModel@9448ba
===========count:1
=========onPause========
=========onSaveInstanceState========
=========onDestroy========
=========onCreate========
=========onStart========
=========onRestoreInstanceState========
=========onResume========
===========viewModel:com.malaysia.myapplication.CustomViewModel@9448ba
=======count:100

根据上一节CompentAcvitity实现ViewModelStoreOwner,ComponentActivity中持有mViewModelStore对象,调用父类Activity中的方法getLastNonConfigurationInstance(),注意在ComponentActivity&Activity中都存在一个静态内部类,容易造成误解,详细流程如下:

ComponentActvity获取getLastNonConfigurationInstance(),返回ActivityNonConfigurationInstances保存的activity对象,该对象指向ComponentActivity中的方法onRetainNonConfigurationInstance,返回的就是持有ViewModelStore对象的NonConfigurationInstances

void ensureViewModelStore() {
    if (mViewModelStore == null) {
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            // Restore the ViewModelStore from NonConfigurationInstances
            mViewModelStore = nc.viewModelStore;
        }
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
        }
    }
}

/**
* Activity
* 
**/
public class Activity extends ContextThemeWrapper {
 
    static final class NonConfigurationInstances {
        Object activity; //对应时ComponentActivity中的NonConfigurationInstances
        HashMap<String, Object> children;
        FragmentManagerNonConfig fragments;
        ArrayMap<String, LoaderManager> loaders;
        VoiceInteractor voiceInteractor;
    }
    
    @Nullable
    public Object getLastNonConfigurationInstance() {
        return mLastNonConfigurationInstances != null
                ? mLastNonConfigurationInstances.activity : null;
    }
    
    NonConfigurationInstances retainNonConfigurationInstances() {
        //onRetainNonConfigurationInstance调用的ComponentActivity中方法
        Object activity = onRetainNonConfigurationInstance();
        ......
        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;
    }
}

/***
* ComponentActivity
*
***/
public class ComponentActivity extends androidx.core.app.ComponentActivity{
    
    static final class NonConfigurationInstances {
        Object custom;
        ViewModelStore viewModelStore;
    }
    
    @Override
    @Nullable
    @SuppressWarnings("deprecation")
    public final Object onRetainNonConfigurationInstance() {
        // Maintain backward compatibility.
        Object custom = onRetainCustomNonConfigurationInstance();

        ViewModelStore viewModelStore = mViewModelStore;
        if (viewModelStore == null) {
            // No one called getViewModelStore(), so see if there was an existing
            // ViewModelStore from our last NonConfigurationInstance
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                viewModelStore = nc.viewModelStore;
            }
        }
        if (viewModelStore == null && custom == null) {
            return null;
        }
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = viewModelStore;
        return nci;
    }
}

SaveStateHandle

上一节中分析在Activity配置发生改变时,ViewModel保存、恢复的原理,在ViewModel创建过程中还可以通过构造函数设置SaveStateHandle来获取Activity、FragmentIntent携带bundle数据,另外在系统内存不足,APP被回收后重新进入可以通过Bundle获取之前保存的数据

SavedStateRegistryOwner

ComponentActivity、Fragment实现该接口,获取SavedStateRegistry

interface SavedStateRegistryOwner : LifecycleOwner {
    /**
     * The [SavedStateRegistry] owned by this SavedStateRegistryOwner
     */
    val savedStateRegistry: SavedStateRegistry
}

class ComponentActivity extends SavedStateRegistryOwner...{

    final SavedStateRegistryController mSavedStateRegistryController =
        SavedStateRegistryController.create(this);
    ......
    @NonNull
    @Override
    public final SavedStateRegistry getSavedStateRegistry() {
        return mSavedStateRegistryController.getSavedStateRegistry();
    }
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        mSavedStateRegistryController.performRestore(savedInstanceState);
    }
    
    @CallSuper
    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        mSavedStateRegistryController.performSave(outState);
    }

}

SavedStateRegistryController

ComponentActivity、Fragment的成员变量,持有一个savedStateRegistry,对saveStateRegistry的方法进行封装(外观模式),减少对外暴露方法数量,在保存、恢复Bundle数据时增加生命周期判断逻辑

class SavedStateRegistryController private constructor(private val owner: SavedStateRegistryOwner) {

    val savedStateRegistry: SavedStateRegistry = SavedStateRegistry()
    private var attached = false
    @MainThread
    fun performAttach() {
        val lifecycle = owner.lifecycle
        check(lifecycle.currentState == Lifecycle.State.INITIALIZED) {
            ("Restarter must be created only during owner's initialization stage")
        }
        lifecycle.addObserver(Recreator(owner))
        savedStateRegistry.performAttach(lifecycle)
        attached = true
    }

    @MainThread
    fun performRestore(savedState: Bundle?) {
        if (!attached) {
            performAttach()
        }
        val lifecycle = owner.lifecycle
        check(!lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
            ("performRestore cannot be called when owner is ${lifecycle.currentState}")
        }
        savedStateRegistry.performRestore(savedState)
    }
    
    @MainThread
    fun performSave(outBundle: Bundle) {
        savedStateRegistry.performSave(outBundle)
    }

    companion object {
        @JvmStatic
        fun create(owner: SavedStateRegistryOwner): SavedStateRegistryController {
            return SavedStateRegistryController(owner)
        }
    }
}

SavedStateRegistry

成员变量components用来存放实现SavedStateProvider接口的对象,需要保存Bundle的数据都必须实现该接口,

class SavedStateRegistry internal constructor() {
    private val components = SafeIterableMap<String, SavedStateProvider>()
    private var attached = false
    private var restoredState: Bundle? = null
    
    /**
    * 上文分析在Activity\Fragment onCreate中调用
    **/
    internal fun performRestore(savedState: Bundle?) {
        check(attached) {
            ("You must call performAttach() before calling " +
                "performRestore(Bundle).")
        }
        check(!isRestored) { "SavedStateRegistry was already restored." }
        restoredState = savedState?.getBundle(SAVED_COMPONENTS_KEY)
        isRestored = true
    }

   /**
    * 遍历所有实现SavedStateProvider接口中回调的Bundle,进行汇总保存到Key为
    *  SAVED_COMPONENTS_KEY的vaule中
    **/
    @MainThread
    @Suppress("INACCESSIBLE_TYPE")
    fun performSave(outBundle: Bundle) {
        val components = Bundle()
        if (restoredState != null) {
            components.putAll(restoredState)
        }
        val it: Iterator<Map.Entry<String, SavedStateProvider>> =
            this.components.iteratorWithAdditions()
        while (it.hasNext()) {
            val (key, value) = it.next()
            components.putBundle(key, value.saveState())
        }
        if (!components.isEmpty) {
            outBundle.putBundle(SAVED_COMPONENTS_KEY, components)
        }
    }

    fun interface SavedStateProvider {
        fun saveState(): Bundle
    }

    private companion object {
        private const val SAVED_COMPONENTS_KEY =
            "androidx.lifecycle.BundlableSavedStateRegistry.key"
    }

}

SavedStateHandleController

回顾SavedStateViewModelFactory中创建ViewModel时,传递SavedStateHandle实现方式,创建controller对象就是SavedStateHandleController

fun <T : ViewModel> create(key: String, modelClass: Class<T>): T {
    ......
    val controller = LegacySavedStateHandleController.create(
        savedStateRegistry, lifecycle, key, defaultArgs
    )
   ......
}

class LegacySavedStateHandleController {
    .......
    static SavedStateHandleController create(SavedStateRegistry registry, Lifecycle lifecycle,
            String key, Bundle defaultArgs) {
        //key为ViewModel的key,疑问点何时注册key为ViewModel的Bundle
        Bundle restoredState = registry.consumeRestoredStateForKey(key);
        //根据Bundles生成SavedStateHandle
        SavedStateHandle handle = SavedStateHandle.createHandle(restoredState, defaultArgs);
        //创建SavedStateHandleController
        SavedStateHandleController controller = new SavedStateHandleController(key, handle);
        controller.attachToLifecycle(registry, lifecycle);
        tryToAddRecreator(registry, lifecycle);
        return controller;
    }
    ......
}

Recreator和OnRecreation

在Activity重新创建时,就会执行到该流程

static final class OnRecreation implements SavedStateRegistry.AutoRecreated {

    @Override
    public void onRecreated(@NonNull SavedStateRegistryOwner owner) {
        if (!(owner instanceof ViewModelStoreOwner)) {
            throw new IllegalStateException(
                    "Internal error: OnRecreation should be registered only on components"
                            + " that implement ViewModelStoreOwner");
        }
        ViewModelStore viewModelStore = ((ViewModelStoreOwner) owner).getViewModelStore();
        SavedStateRegistry savedStateRegistry = owner.getSavedStateRegistry();
        for (String key : viewModelStore.keys()) {
            ViewModel viewModel = viewModelStore.get(key);
            attachHandleIfNeeded(viewModel, savedStateRegistry, owner.getLifecycle());
        }
        if (!viewModelStore.keys().isEmpty()) {
            savedStateRegistry.runOnNextRecreation(OnRecreation.class);
        }
    }