Savedstate 源码分析

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

Android 应用在因系统资源限制进程被杀死时可通过 onSaveInstanceState-onRestoreInstanceState 保存一些必要数据用于在页面重建时恢复页面 savedstate 对此进行了封装,它与 ViewModel 的区别:
用于保留界面状态的选项

源码分析

来看一下 onSaveInstanceState 和 onCreate 两处保存和恢复数据的地方

// androidx.activity.ComponentActivity
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        SavedStateRegistryOwner {

    // 静态方法创建 SavedStateRegistryController 对象
    final SavedStateRegistryController mSavedStateRegistryController =
            SavedStateRegistryController.create(this);

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        // 恢复数据
        mSavedStateRegistryController.performRestore(savedInstanceState);
    }

    @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);
    }

    @NonNull
    @Override
    public final SavedStateRegistry getSavedStateRegistry() {
        return mSavedStateRegistryController.getSavedStateRegistry();
    }

}

ComponentActivity 实现了 SavedStateRegistryOwner 接口重写 getSavedStateRegistry 方法返回一个 SavedStateRegistry 并且在 onCreate 和 onSaveInstanceState 中分别调用了 SavedStateRegistryController 保存和恢复数据的方法

public final class SavedStateRegistryController {
    private final SavedStateRegistryOwner mOwner;
    private final SavedStateRegistry mRegistry;

    private SavedStateRegistryController(SavedStateRegistryOwner owner) {
        mOwner = owner;
        // 创建 SavedStateRegistry 对象
        mRegistry = new SavedStateRegistry();
    }

    @NonNull
    public SavedStateRegistry getSavedStateRegistry() {
        // 返回 SavedStateRegistry 对象
        return mRegistry;
    }

    @MainThread
    public void performRestore(@Nullable Bundle savedState) {
        Lifecycle lifecycle = mOwner.getLifecycle();
        if (lifecycle.getCurrentState() != Lifecycle.State.INITIALIZED) {
            throw new IllegalStateException("Restarter must be created only during "
                    + "owner's initialization stage");
        }
        lifecycle.addObserver(new Recreator(mOwner));
        // 转发给 SavedStateRegistry
        mRegistry.performRestore(lifecycle, savedState);
    }

    @MainThread
    public void performSave(@NonNull Bundle outBundle) {
        // 转发给 SavedStateRegistry
        mRegistry.performSave(outBundle);
    }

    @NonNull
    public static SavedStateRegistryController create(@NonNull SavedStateRegistryOwner owner) {
        return new SavedStateRegistryController(owner);
    }

}

SavedStateRegistryController 就是简单的对 SavedStateRegistry的包装,在构造方法里创建了 SavedStateRegistry 对象,保存和恢复数据的方法直接转发给了 SavedStateRegistry

public final class SavedStateRegistry {
    private static final String SAVED_COMPONENTS_KEY =
            "androidx.lifecycle.BundlableSavedStateRegistry.key";

    private SafeIterableMap<String, SavedStateProvider> mComponents =
            new SafeIterableMap<>();
    @Nullable
    private Bundle mRestoredState;
    private boolean mRestored;
    private Recreator.SavedStateProvider mRecreatorProvider;
    boolean mAllowingSavingState = true;

    SavedStateRegistry() {
    }

    @MainThread
    @Nullable
    // 根据 key 取出在组件被杀死时保存的数据
    public Bundle consumeRestoredStateForKey(@NonNull String key) {
    	// 在数据恢复前消费抛出异常
        if (!mRestored) {
            throw new IllegalStateException("You can consumeRestoredStateForKey "
                    + "only after su
                    + per.onCreate of corresponding component");
        }
        // 如果恢复的数据不为空
        if (mRestoredState != null) {
        	// 根据 key 取出保存的数据
            Bundle result = mRestoredState.getBundle(key);
            // 取出后就移除第二次再取就返回 null 了
            mRestoredState.remove(key);
            // 如果全部取出则置为 null
            if (mRestoredState.isEmpty()) {
                mRestoredState = null;
            }
            return result;
        }
        return null;
    }

    @MainThread
    // 注册要在组件被杀死时保存数据的来源
    public void registerSavedStateProvider(@NonNull String key,
            @NonNull SavedStateProvider provider) {
        // 保存到 map 中    	
        SavedStateProvider previous = mComponents.putIfAbsent(key, provider);
        // 重复注册同一个 key 抛出异常
        if (previous != null) {
            throw new IllegalArgumentException("SavedStateProvider with the given key is"
                    + " already registered");
        }
    }

    @MainThread
    // 解注册
    public void unregisterSavedStateProvider(@NonNull String key) {
        mComponents.remove(key);
    }

	public interface SavedStateProvider {
        // 在组件被杀死之前调用用于返回要在页面重建后恢复的数据
        Bundle saveState();
    }
}

SavedStateRegistry 维护了一个 map 对象 key 是一个字符串 value 是一个 SavedStateProvider 接口只有一个方法,需要在组件被杀死时保存数据的地方实现此方法在组件被杀死前调用,在 performSave 时保存

	// androidx.savedstate.SavedStateRegistry#performSave
    void performSave(@NonNull Bundle outBundle) {
        Bundle components = new Bundle();
        // 如果还有上次重建时保存并且没有取出的数据再次保存
        if (mRestoredState != null) {
            components.putAll(mRestoredState);
        }
        // 遍历要保存数据的来源 map 调用其 saveState 方法保存
        for (Iterator<Map.Entry<String, SavedStateProvider>> it =
                mComponents.iteratorWithAdditions(); it.hasNext(); ) {
            Map.Entry<String, SavedStateProvider> entry1 = it.next();
            components.putBundle(entry1.getKey(), entry1.getValue().saveState());
        }
        // 保存到 outBundle 中
        // outBundle 是 androidx.activity.ComponentActivity#onSaveInstanceState 方法传过来的
        outBundle.putBundle(SAVED_COMPONENTS_KEY, components);
    }

    @MainThread
    void performRestore(@NonNull Lifecycle lifecycle, @Nullable Bundle savedState) {
    	// 重复调用就抛出异常
        if (mRestored) {
            throw new IllegalStateException("SavedStateRegistry was already restored.");
        }
        // savedState 是 androidx.activity.ComponentActivity#onCreate 中传过来的
        if (savedState != null) {
        	// 取出 performSave 中保存的数据
            mRestoredState = savedState.getBundle(SAVED_COMPONENTS_KEY);
        }

		// 代码省略 ..
		
		// 标记已恢复
        mRestored = true;
    }

Savedstate 源码比较少也比较简单就是对 onSaveInstanceState-onCreate 的包装扩展给开发者多一种选择来处理应用被杀死需要保存数据的场景

SavedStateHandle

ViewModel 只能处理系统配置更改引起的页面重建,当系统资源限制应用被杀死时 ViewModel 也被杀死了 SavedStateHandle 的引入使得开发者可以通过 ViewModel 来处理系统资源限制保存恢复数据相当于是对 ViewModel 功能的扩展。之前分析 ViewModel 的时候已经看到了
androidx.activity.ComponentActivity 实现了 HasDefaultViewModelProviderFactory 接口重写了 getDefaultViewModelProviderFactory 方法返回了 SavedStateViewModelFactory 对象并且在 create 中创建 ViewModel 对象时判断构造方法中是否有 SavedStateHandle 参数

	// androidx.lifecycle.SavedStateViewModelFactory#create(java.lang.String, java.lang.Class<T>)
    public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
        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);
        }
        if (constructor == null) {
        	// 如果构造方法里没有 ViewModel 参数到这里就返回了
            return mFactory.create(modelClass);
        }

		// 静态方法创建 SavedStateHandleController 对象
        SavedStateHandleController controller = SavedStateHandleController.create(
                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
        try {
            T viewmodel;
            // 如果是 AndroidViewModel 子类
            if (isAndroidViewModel && mApplication != null) {
      			// 构造方法中传入 SavedStateHandle
                viewmodel = constructor.newInstance(mApplication, controller.getHandle());
            } else {
            	// 构造方法中传入 SavedStateHandle
                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());
        }
    }

	// androidx.lifecycle.SavedStateHandleController#create
    static SavedStateHandleController create(SavedStateRegistry registry, Lifecycle lifecycle,
            String key, Bundle defaultArgs) {
        // 根据 key 恢复数据    
        Bundle restoredState = registry.consumeRestoredStateForKey(key);
        // 使用恢复的数据创建 SavedStateHandle 对象
        SavedStateHandle handle = SavedStateHandle.createHandle(restoredState, defaultArgs);
        SavedStateHandleController controller = new SavedStateHandleController(key, handle);
        // 关联生命周期注册要保存的数据源
        controller.attachToLifecycle(registry, lifecycle);
        tryToAddRecreator(registry, lifecycle);
        return controller;
    }

在创建有以 SavedStateHandle 为构造参数的 ViewModel 时会使用恢复的数据创建
SavedStateHandle 对象作为参数用于创建 ViewModel 对象

	// androidx.lifecycle.SavedStateHandleController#attachToLifecycle
    void attachToLifecycle(SavedStateRegistry registry, Lifecycle lifecycle) {
        if (mIsAttached) {
            throw new IllegalStateException("Already attached to lifecycleOwner");
        }
        mIsAttached = true;
        lifecycle.addObserver(this);
        // 注册要保存的数据源,第二个参数是 SavedStateHandle 中的 SavedStateProvider
        registry.registerSavedStateProvider(mKey, mHandle.savedStateProvider());
    }

当应用被杀死时会调用所有 SavedStateProvider 的 saveState 方法

public final class SavedStateHandle {
	// 最终要保存的数据
    final Map<String, Object> mRegular;
    // SavedStateHandle 也支持直接设置 SavedStateProvider 会存到这个 map 里
    final Map<String, SavedStateProvider> mSavedStateProviders = new HashMap<>();
    // 可以通过 key 返回一个 LiveData 对象在创建对象后会保存到这里下次不用重复创建
    private final Map<String, SavingStateLiveData<?>> mLiveDatas = new HashMap<>();

    private static final String VALUES = "values";
    private static final String KEYS = "keys";

    private final SavedStateProvider mSavedStateProvider = new SavedStateProvider() {
        @SuppressWarnings("unchecked")
        @NonNull
        @Override
        public Bundle saveState() {
            // 遍历设置的 SavedStateProvider 调用其 saveState 方法返回一个 Bundle 
            // 保存到 mRegular 中
            Map<String, SavedStateProvider> map = new HashMap<>(mSavedStateProviders);
            for (Map.Entry<String, SavedStateProvider> entry : map.entrySet()) {
                Bundle savedState = entry.getValue().saveState();
                set(entry.getKey(), savedState);
            }
            // 遍历 mRegular 把 key-value 分别保存到两个列表中
            Set<String> 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();
            // 把两个列表存储到 Bundle 中返回出去存储到 
            // androidx.activity.ComponentActivity#onSaveInstanceState 方法的 Bundle
            // Bundle 存 Bundle 一层套一层 
            res.putParcelableArrayList("keys", keys);
            res.putParcelableArrayList("values", value);
            return res;
        }
    };


    public SavedStateHandle(@NonNull Map<String, Object> initialState) {
        mRegular = new HashMap<>(initialState);
    }

    public SavedStateHandle() {
        mRegular = new HashMap<>();
    }

	// 上面已经分析过 androidx.activity.ComponentActivity 默认返回的 ViewModelFactory 是 
	// androidx.lifecycle.SavedStateViewModelFactory 在 create 里会创建 SavedStateHandleController 对象
	// 在 SavedStateHandleController 的 create 方法里会调用此方法创建 SavedStateHandle 对象
    static SavedStateHandle createHandle(@Nullable Bundle restoredState,
            @Nullable Bundle defaultState) {
         // restoredState 是通过 androidx.savedstate.SavedStateRegistry#consumeRestoredStateForKey 返回的 Bundle 
         //  如果 restoredState 为 null 说明是正常打开页面或者页面销毁时并没有保存此 key
        if (restoredState == null && defaultState == null) {
            return new SavedStateHandle();
        }

        Map<String, Object> state = new HashMap<>();
        // 默认值在 androidx.activity.ComponentActivity#getDefaultViewModelProviderFactory
        // 方法里会尝试从 getIntent 方法中取
        if (defaultState != null) {
            for (String key : defaultState.keySet()) {
                state.put(key, defaultState.get(key));
            }
        }

        if (restoredState == null) {
        	// 如果 restoredState 就使用默认值创建一个 SavedStateHandle 对象返回
            return new SavedStateHandle(state);
        }

		// 取出上面分析保存的 key-value
        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));
        }
        // 返回 SavedStateHandle 对象 
        return new SavedStateHandle(state);
    }

    @NonNull
    SavedStateProvider savedStateProvider() {
        return mSavedStateProvider;
    }

}

SavedStateHandle 中有一个 SavedStateProvider 对象 mSavedStateProvider 并且也支持额外设置 SavedStateProvider 在页面被销毁调用 mSavedStateProvider 的 saveState 方法时遍历所有设置的 SavedStateProvider 调用 saveState 保存数据,并且每一层返回的都是 Bundle 对象,在创建 ViewModel 对象时会创建 SavedStateHandle 对象并且尝试恢复之前保存的数据,这样就可以通过 ViewModel 对象拿到之前保存的数据了


总结

SavedState 是对 onSaveInstanceState-onRestoreInstanceState 机制的封装可以处理因为系统资源限制应用被杀死时保存简单数据在页面重建时恢复
因为 ViewModel 只能处理系统配置更改引起的页面重建上述情况并不能处理 SavedStateHandle 是利用 SavedState 对 ViewModel 的扩展让开发者可以通过 ViewModel 处理上述场景,当 ViewModel 的构造方法中有 SavedStateHandle 参数时系统默认就会尝试恢复上次应用被杀死时保存的数据

参考与感谢

从源码看 Jetpack(7)- SavedStateHandle 源码详解
【背上Jetpack】绝不丢失的状态 androidx SaveState ViewModel-SaveState 分析
【安卓开发系列 – APP】JetPack – SavedState

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值