ViewModel源码阅读(二)SavedStateHandle的基本数据缓存原理

前言

阅读本篇文章前最好先看上篇文章ViewModel源码阅读(一)ViewModel的生命周期
在阅读SavedStateHandle之前,我们需要搞清上篇文章通过getLastNonConfigurationInstance和onRetainNonConfigurationInstance存储的数据,与通过onSaveInstanceState和Bundle存储的数据有什么不同
我这里直接就说出结论了
getLastNonConfigurationInstance是通过NonConfigurationInstances保存状态的,这个状态可以获取的前提是进程没有被销毁
onSaveInstanceState中Bundle是通过Parcel保存状态的,这种保存的状态是非依附于进程的,当前进程被杀死,状态也是保留的
详细可以参考这篇文章,这里就不展开讨论了

在上面逻辑基础上,和上篇文章分析的ViewModel生命周期,我们可以推测出,ViewModel在进程被系统杀死时,再恢复时,是重新创建实例的,所以ViewModel引入了SavedStateHandle,来做轻量数据状态暂存

分析代码

这块的代码我第一次看的时候有点绕,因为关联类太多了,所以这块代码单独独立出来
下面开始阅读源码

  @NonNull
    @Override
    public  T create(@NonNull String key, @NonNull Class modelClass) {
        boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
        Constructor constructor;
//获取构造函数,判断是否需要传入SavedStateHandle
        if (isAndroidViewModel && mApplication != null) {
            constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
        } else {
            constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
        }
        // doesn't need SavedStateHandle
        if (constructor == null) {
            return mFactory.create(modelClass);
        }
//核心方法,用来创建Handle的关键代码
//此处传入了一个mSavedStateRegistry 和mLifecycle 作用暂时未知
//key和mDefaultArgs分别对应ViewModel的唯一标识和getIntent中暂存的数据
        SavedStateHandleController controller = SavedStateHandleController.create(
                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
        try {
            T viewmodel;
//下面的代码就是传入handle的
            if (isAndroidViewModel && mApplication != null) {
                viewmodel = constructor.newInstance(mApplication, controller.getHandle());
            } else {
                viewmodel = constructor.newInstance(controller.getHandle());
            }
            viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
            return viewmodel;
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Failed to access " + modelClass, e);
        } catch (InstantiationException e) {
            throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException("An exception happened in constructor of "
                    + modelClass, e.getCause());
        }
    }

代码集中在create方法,我们继续研究create里是都创建了什么

    static SavedStateHandleController create(SavedStateRegistry registry, Lifecycle lifecycle,
            String key, Bundle defaultArgs) {
//通过registry获取Bundle ,此处推测registry应该也是一个存储数据的封装类,此处代码应该是一个恢复获取状态的代码
        Bundle restoredState = registry.consumeRestoredStateForKey(key);
//创建ViewModel中的Handle
        SavedStateHandle handle = SavedStateHandle.createHandle(restoredState, defaultArgs);
//创建对外提供的controller
        SavedStateHandleController controller = new SavedStateHandleController(key, handle);
//下面这两段代码等将SavedStateRegistry研究明白再看
        controller.attachToLifecycle(registry, lifecycle);
        tryToAddRecreator(registry, lifecycle);
        return controller;
    }

上面的代码大体就是一个SavedStateHandleController创建过程,涉及到SavedStateRegistry,SavedStateHandleController两个类和controller.attachToLifecycle,tryToAddRecreator两个方法
先研究SavedStateRegistry
在SavedStateViewModelFactory发现SavedStateRegistry是SavedStateViewModelFactory构造函数在SavedStateRegistryOwner中获取的,SavedStateRegistryOwner是在CommponentActivity中实现的,主要是一个getSavedStateRegistry的实现
而getSavedStateRegistry方法设计到mSavedStateRegistryController变量。。。
mSavedStateRegistryController变量在类成员变量中初始化,代码如下

ComponentActivity
    final SavedStateRegistryController mSavedStateRegistryController =
            SavedStateRegistryController.create(this);

SavedStateRegistryController的代码如下,

public final class SavedStateRegistryController {
    private final SavedStateRegistryOwner mOwner;
    private final SavedStateRegistry mRegistry;
//在构造函数传入一个Lifecycle的Owner
    private SavedStateRegistryController(SavedStateRegistryOwner owner) {
        mOwner = owner;
//这个玩意整体看了下,应该是真正零时缓存数据的操作类(google 你来解释下为啥要套的这么深?没有更好的方案了吗?)
        mRegistry = new SavedStateRegistry();
    }

  //提供对外使用的操作存储类
    @NonNull
    public SavedStateRegistry getSavedStateRegistry() {
        return mRegistry;
    }

//这里是核心代码,一行一行注释,主要是数据使用前封装
//这里主要是将恢复后的数据拿到,而且通过lifecycle将获取时机控制在onCreate中
    @MainThread
    public void performRestore(@Nullable Bundle savedState) {
//此处拿到在ComponentActivity实例的SavedStateRegistryOwner
        Lifecycle lifecycle = mOwner.getLifecycle();
//如果Lifecycle.State的状态在OnCreate之前会回调到这里,说明是有问题的,抛出异常
        if (lifecycle.getCurrentState() != Lifecycle.State.INITIALIZED) {
            throw new IllegalStateException("Restarter must be created only during "
                    + "owner's initialization stage");
        }
//这里做个一个一次性事件的添加,为啥是一次性?Recreator里面会解答
        lifecycle.addObserver(new Recreator(mOwner));
//将savedState里的Bundle读出来,下面会分析
        mRegistry.performRestore(lifecycle, savedState);
    }

//数据保存前封装 outBundle就是onSaveInstanceState中的Bundle
    @MainThread
    public void performSave(@NonNull Bundle outBundle) {
        mRegistry.performSave(outBundle);
    }

    //提供快捷创建函数
    @NonNull
    public static SavedStateRegistryController create(@NonNull SavedStateRegistryOwner owner) {
        return new SavedStateRegistryController(owner);
    }
}

上面这段代码主要有三个工作内容
1,将ComponentActivity的lifeCycle拿到
2,在创建真正的读取保存类SavedStateRegistry
3,控制将恢复数据的时机控制在onCreate,并封装SavedStateRegistry

最后看SavedStateRegistry几个关键代码


//这里savedState 是ComponentActivity里onCreate中的savedInstanceState 通过mSavedStateRegistryController.performRestore传入
   @MainThread
    void performRestore(@NonNull Lifecycle lifecycle, @Nullable Bundle savedState) {
        if (mRestored) {
            throw new IllegalStateException("SavedStateRegistry was already restored.");
        }
//这里获取到恢复的savedState里面的数据在 performSave 中可以看到格式
        if (savedState != null) {
//此处的mRestoredState在SavedStateHandleController中的 registry.consumeRestoredStateForKey会用到
            mRestoredState = savedState.getBundle(SAVED_COMPONENTS_KEY);
        }
//做了一个监听,如果执行了Lifecycle.Event.ON_STOP 的话,记录mAllowingSavingState,用来判断是否是正常流程
        lifecycle.addObserver(new GenericLifecycleObserver() {
            @Override
            public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_START) {
                    mAllowingSavingState = true;
                } else if (event == Lifecycle.Event.ON_STOP) {
                    mAllowingSavingState = false;
                }
            }
        });
//做了一个是否恢复的标记,
        mRestored = true;
    }
这里是当onSaveInstanceState执行时,执行的代码
 @MainThread
    void performSave(@NonNull Bundle outBundle) {
//将内存中的数据全部装进来
        Bundle components = new Bundle();
        if (mRestoredState != null) {
            components.putAll(mRestoredState);
        }
//遍历各个生成的handle,保存handle中的数据,后面看handler源码就会发现每个handle都会保存一个SavedStateProvider
        for (Iterator> it =
                mComponents.iteratorWithAdditions(); it.hasNext(); ) {
            Map.Entry entry1 = it.next();
            components.putBundle(entry1.getKey(), entry1.getValue().saveState());
        }
        outBundle.putBundle(SAVED_COMPONENTS_KEY, components);
    }

上面代码主要做了一个数据读取和保存,和我们平时写普通的数据零时保存一样,只是做了封装,mRestoredState作为存储和读取的所有数据的全局变量
最后看下ComponentActivity

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
       //代码不多,没做代码省略,这句话执行后,相当于就是从恢复中拿到了数据
        mSavedStateRegistryController.performRestore(savedInstanceState);
        mContextAwareHelper.dispatchOnContextAvailable(this);
        super.onCreate(savedInstanceState);
        ReportFragment.injectIfNeededIn(this);
        if (mContentLayoutId != 0) {
            setContentView(mContentLayoutId);
        }
    }
  @CallSuper
    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        Lifecycle lifecycle = getLifecycle();
        if (lifecycle instanceof LifecycleRegistry) {
            ((LifecycleRegistry) lifecycle).setCurrentState(Lifecycle.State.CREATED);
        }
        super.onSaveInstanceState(outState);
//这句话执行后,将数据零时存储在恢复区
        mSavedStateRegistryController.performSave(outState);
    }

所以通过以上代码的阅读,我们已经发现,SavedStateHandle的核心逻辑就是通过onSaveInstanceState做临时存储,数据恢复只是封装了两层,做了很多逻辑判断
SavedStateRegistryController->SavedStateRegistry->执行恢复存储。
再回到SavedStateHandleController

static SavedStateHandleController create(SavedStateRegistry registry, Lifecycle lifecycle,
            String key, Bundle defaultArgs) {
//这行代码,下面会简单看下,主要是为了去哪在系统恢复Activity时,通过getIntent中的内容
        Bundle restoredState = registry.consumeRestoredStateForKey(key);
//这里创建Handle核心代码
        SavedStateHandle handle = SavedStateHandle.createHandle(restoredState, defaultArgs);
//创建controller 主要是绑定registry数据和handle中mSavedStateProvider的关系
        SavedStateHandleController controller = new SavedStateHandleController(key, handle);
        controller.attachToLifecycle(registry, lifecycle);
        tryToAddRecreator(registry, lifecycle);
        return controller;
    }

先简单看下consumeRestoredStateForKey中的东西

    @MainThread
    @Nullable
    public Bundle consumeRestoredStateForKey(@NonNull String key) {
        if (!mRestored) {
            throw new IllegalStateException("You can consumeRestoredStateForKey "
                    + "only after super.onCreate of corresponding component");
        }
        if (mRestoredState != null) {
            Bundle result = mRestoredState.getBundle(key);
            mRestoredState.remove(key);
            if (mRestoredState.isEmpty()) {
                mRestoredState = null;
            }
            return result;
        }
        return null;
    }

代码很简单,主要是通过ViewModel唯一关键字获取mRestoredState里存储的Bundle,而这个mRestoredState我们前面代码已经知道就是用来做activity销毁前存储和activtiy恢复时读取的Bundle,所以这里相当于通过Viewmodle的Key获取在ViewModel中临时存储的数据
再看createHandle的代码


    static SavedStateHandle createHandle(@Nullable Bundle restoredState,
            @Nullable Bundle defaultState) {
//如果没有需要缓存或者恢复的数据,直接创建SavedStateHandle
        if (restoredState == null && defaultState == null) {
            return new SavedStateHandle();
        }
        Map state = new HashMap<>();
        if (defaultState != null) {
            for (String key : defaultState.keySet()) {
                state.put(key, defaultState.get(key));
            }
        }
//如果有需要缓存的数据创建且没有恢复数据的情况,一个带缓存数据的SavedStateHandle

        if (restoredState == null) {
            return new SavedStateHandle(state);
        }

        ArrayList keys = restoredState.getParcelableArrayList(KEYS);
        ArrayList values = restoredState.getParcelableArrayList(VALUES);
        if (keys == null || values == null || keys.size() != values.size()) {
            throw new IllegalStateException("Invalid bundle passed as restored state");
        }
        for (int i = 0; i < keys.size(); i++) {
            state.put((String) keys.get(i), values.get(i));
        }
//如果两个都有,那就两个都塞进去
        return new SavedStateHandle(state);
    }

这里需要看下handle把数据存到哪里了,在构造函数中


    /**
     * Creates a handle with the given initial arguments.
     */
    public SavedStateHandle(@NonNull Map initialState) {
        mRegular = new HashMap<>(initialState);
    }

    /**
     * Creates a handle with the empty state.
     */
    public SavedStateHandle() {
        mRegular = new HashMap<>();
    }

我们发现刚刚的数据全部塞到mRegular中了
这个mRegular就是一个Map,并且提供给外部使用


    /**
     * Returns a value associated with the given key.
     */
    @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"})
    @MainThread
    @Nullable
    public  T get(@NonNull String key) {
        return (T) mRegular.get(key);
    }

    /**
     * Associate the given value with the key. The value must have a type that could be stored in
     * {@link android.os.Bundle}
     *
     * @param  any type that can be accepted by Bundle.
     */
    @MainThread
    public  void set(@NonNull String key, @Nullable T value) {
        validateValue(value);
        @SuppressWarnings("unchecked")
        MutableLiveData mutableLiveData = (MutableLiveData) mLiveDatas.get(key);
        if (mutableLiveData != null) {
            // it will set value;
            mutableLiveData.setValue(value);
        } else {
            mRegular.put(key, value);
        }
    }

也就是说handle主要是提供了一个mRegular的Map提供业务层读取和存储(甚至提供了一个LiveData,这里就不展开了),但是真实存储的时候,我们发现是下面这段代码(上面已经阅读过,需要重新看下)

 @MainThread
    void performSave(@NonNull Bundle outBundle) {
...
        for (Iterator> it =
                mComponents.iteratorWithAdditions(); it.hasNext(); ) {
            Map.Entry entry1 = it.next();
            components.putBundle(entry1.getKey(), entry1.getValue().saveState());
        }
        outBundle.putBundle(SAVED_COMPONENTS_KEY, components);
    }

这里发现是遍历的mComponents中的SavedStateProvider,执行的saveState方法,在Handle中也存在这样一段代码

    private final SavedStateProvider mSavedStateProvider = new SavedStateProvider() {
        @SuppressWarnings("unchecked")
        @NonNull
        @Override
        public Bundle saveState() {
            // Get the saved state from each SavedStateProvider registered with this
            // SavedStateHandle, iterating through a copy to avoid re-entrance
            Map map = new HashMap<>(mSavedStateProviders);
            for (Map.Entry entry : map.entrySet()) {
                Bundle savedState = entry.getValue().saveState();
                set(entry.getKey(), savedState);
            }
            // Convert the Map of current values into a Bundle
            Set keySet = mRegular.keySet();
            ArrayList keys = new ArrayList(keySet.size());
            ArrayList value = new ArrayList(keys.size());
            for (String key : keySet) {
                keys.add(key);
                value.add(mRegular.get(key));
            }

            Bundle res = new Bundle();
            // "parcelable" arraylists - lol
            res.putParcelableArrayList("keys", keys);
            res.putParcelableArrayList("values", value);
            return res;
        }
    };

上面的代码没有写注释,大体意思就是把mRegular中的数据塞到Bundle里,我们可以联想,应该是在performSave时,调用handle中的SavedStateProvider里的saveState方法获取Bundle并保存的,那就是handle中的SavedStateProvider会存到SavedStateRegistry的mComponents中。。但是在哪塞入的呢?我们再回到SavedStateHandleController中看下一个方法

  static SavedStateHandleController create(SavedStateRegistry registry, Lifecycle lifecycle,
            String key, Bundle defaultArgs) {
        Bundle restoredState = registry.consumeRestoredStateForKey(key);
        SavedStateHandle handle = SavedStateHandle.createHandle(restoredState, defaultArgs);
        SavedStateHandleController controller = new SavedStateHandleController(key, handle);
//目前只有下面这两句可能会将handle里的SavedStateProvider和SavedStateRegistry里的mComponents做数据绑定了
        controller.attachToLifecycle(registry, lifecycle);
        tryToAddRecreator(registry, lifecycle);
        return controller;
    }

先看attachToLifecycle

    void attachToLifecycle(SavedStateRegistry registry, Lifecycle lifecycle) {
        if (mIsAttached) {
            throw new IllegalStateException("Already attached to lifecycleOwner");
        }
        mIsAttached = true;
        lifecycle.addObserver(this);
//这句话明显感觉就是用来绑定数据的
        registry.registerSavedStateProvider(mKey, mHandle.savedStateProvider());
    }

再看registerSavedStateProvider

    @MainThread
    public void registerSavedStateProvider(@NonNull String key,
            @NonNull SavedStateProvider provider) {
//这里果然做了数据put
        SavedStateProvider previous = mComponents.putIfAbsent(key, provider);
        if (previous != null) {
            throw new IllegalArgumentException("SavedStateProvider with the given key is"
                    + " already registered");
        }
    }

SafeIterableMap mComponents

    public V putIfAbsent(@NonNull K key, @NonNull V v) {
        Entry entry = get(key);
        if (entry != null) {
            return entry.mValue;
        }
        put(key, v);
        return null;
    }

看过最后这块代码,我们整个Handle的逻辑就很清晰了,下面说下文字流程

1在通过SavedStateViewModelFactory创建ViewModel时,先通过构造函数入参判断是否存在SavedStateHandle入参,如果存在就执行创建SavedStateHandleController
2通过SavedStateHandleController.create创建SavedStateHandleController,在创建SavedStateHandleController时将Activtiy中实现的SavedStateRegistryOwner通过getSavedStateRegistry传入mSavedStateRegistry
3mSavedStateRegistry在ComponentActivity通过SavedStateRegistryController.create()实例,并且在ComponentActivity中onCreate里执行了performRestore方法,在onSaveInstanceState里执行了performSave方法
4在SavedStateHandleController创建时,先获取mSavedStateRegistry在ComponentActivity里的onCreate是获取到的数据,并且将数据塞到创建的SavedStateHandle中的mRegular里
5再将SavedStateHandle封装到 SavedStateHandleController中,并将handel里的mSavedStateProvider塞到mSavedStateRegistry中的mComponents中
6当Activity被系统杀死时,执行onSaveInstanceState,触发mSavedStateRegistry.performSave
7在performSave时,遍历mComponents,执行mSavedStateProvider的saveState封装数据,塞到onSaveInstanceState的Bundle里

最后上自己画的handle代码简易逻辑图


handle代码简易逻辑图

你可能感兴趣的:(ViewModel源码阅读(二)SavedStateHandle的基本数据缓存原理)