一、为什么使用SavedStateHandle
Activity被意外销毁的情况有两种
- 资源配置变更导致
Activity销毁,例如屏幕旋转 - 系统资源限制导致
Activity被销毁
ViewModel可以解决第一种情况下的数据恢复问题,但是对于第二种,则需要依赖原生提供的数据保护与恢复机制,即onSaveInstanceState(Bundle)和onRestoreInstanceState(Bundle)
onSaveInstanceState(Bundle) 方法保存的数据在资源配置更改或 Activity 被意外杀死时都会被保留,但存在存储容量和存取速度的限制。因为 Bundle 有着容量限制,不适合用于存储大量数据,且 onSaveInstanceState(Bundle) 方法会将数据序列化到磁盘,如果要保存的数据很复杂,序列化会消耗大量的内存和时间。
所以 onSaveInstanceState(Bundle) 仅适合用于存储少量的简单类型的数据
对于Activity的第二种销毁情况,数据的保存和恢复被限制在Activity 的特定方法里,无法直接在ViewModel中决定哪些数据需要保留,也无法直接拿到恢复后的数据。
SavedStateHandle组件可以看作是ViewModel功能的扩展,解决ViewModel无法感知onSaveInstanceState被触发的问题
二、基本使用
2.1 简单使用
SavedStateHandle的使用流程一般为:
- 将
SavedStateHandle作为ViewModel的构造参数 ViewModel内部通过SavedStateHandle.getLiveData方法来生成一个LiveData对象,LiveData中的数据即我们想要持久化保存的数据。如果是全新启动Activity,LiveData中保存的值为null;如果是重建后的Activity,LiveData中保存的值则为重建前其自身的值- 传给
getLiveData方法的String参数是一个唯一Key,最终保存到Bundle中的键值对就以该值作为Key,以LiveData的值作为value
看一下SavedStateHandle实例演示
将SavedStateHandle作为ViewModel的构造参数
class SavedStateViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
companion object {
private const val KEY_NAME = "keyName"
}
//通过 SavedStateHandle.getLiveData方法来生成一个 LiveData 对象
val nameLiveData = savedStateHandle.getLiveData<String>(KEY_NAME)
val blogLiveData = MutableLiveData<String>()
}
ViewModel使用
class MainActivity : AppCompatActivity() {
private val savedStateViewModel by lazy {
ViewModelProvider(this).get(SavedStateViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
log("savedStateViewModel: $savedStateViewModel")
log("savedStateViewModel.name: ${savedStateViewModel.nameLiveData.value}")
log("savedStateViewModel.blog: ${savedStateViewModel.blogLiveData.value}")
log("onCreate")
btn_test.setOnClickListener {
savedStateViewModel.nameLiveData.value = "SavedStateViewModel"
savedStateViewModel.blogLiveData.value = "https://https://zhewendev.github.io/"
}
}
private fun log(log: String) {
Log.e("MainActivity", log)
}
}
//打印结果
/**MainActivity第一次启动时**/
E/MainActivity: savedStateViewModel: com.zhewen.navigationcodelab.navigation.SavedStateViewModel@53e1b17
E/MainActivity: savedStateViewModel.name: null
E/MainActivity: savedStateViewModel.blog: null
E/MainActivity: onCreate
/**按钮点击赋值后,按Home键退出,再重新进入*/
E/MainActivity: savedStateViewModel: com.zhewen.navigationcodelab.navigation.SavedStateViewModel@b613350
E/MainActivity: savedStateViewModel.name: SavedStateViewModel
E/MainActivity: savedStateViewModel.blog: null
E/MainActivity: onCreate
可通过打开开发者模式中"不保留活动"的选项来模拟 Activity由于系统内存不足被销毁的情况
从log的打印结果可知,ViewModel已经被销毁重新构建了一个,但是通过SavedStateHandle 构建的 nameLiveData 中还保留着之前的值
SavedStateHandle 其实也是通过封装 onSaveInstanceState(Bundle)和 onCreate(Bundle)两个方法来实现的
SavedStateHandle 会在 Activity 被销毁时通过onSaveInstanceState(Bundle)方法将数据保存在 Bundle 中,在重建时又将数据从 onCreate(Bundle?)中取出,开发者只负责向 SavedStateHandle 存取数据即可,并不需要和 Activity 直接做交互,从而简化了整个开发流程
2.2 支持类型
保留在 SavedStateHandle 中的数据将作为Bundle与 Activity 或 Fragment 的 onSaveInstanceState(Bundle)其余部分一起保存和恢复。
直接支持类型
默认情况下,您可以对 SavedStateHandle 调用 set() 和 get(),以处理与 Bundle 相同的数据类型
| 类型/类支持 | 数组支持 |
|---|---|
double | double[] |
int | int[] |
long | long[] |
String | String[] |
byte | byte[] |
char | char[] |
CharSequence | CharSequence[] |
float | float[] |
Parcelable | Parcelable[] |
Serializable | Serializable[] |
short | short[] |
SparseArray | |
Binder | |
Bundle | |
ArrayList | |
Size (only in API 21+) | |
SizeF (only in API 21+) |
如果该类没有扩展上述列表中的任何一项,可考虑通过@Parcelize kotlin注解或直接实现Parcelable来使该类变为Parcelable类型。
保存非Parcelable类
如果某个类未实现 Parcelable 或 Serializable 且不能修改为实现这些接口之一,则无法直接将该类的实例保存到 SavedStateHandle 中。
Lifecycle 2.0.0-alpha03开始, SavedStateHandle允许保存任何对象。
具体方法:使用setSavedStateProvider()方法提供自己的逻辑用于将对象作为Bundle来保存和恢复
看一下官方提供的示例
class TempFileViewModel : ViewModel() {
private var tempFile: File? = null
fun createOrGetTempFile(): File {
return tempFile ?: File.createTempFile("temp", null).also {
tempFile = it
}
}
}
为确保临时文件在 Activity 的进程终止随后又恢复后不会丢失,TempFileViewModel 可以使用 SavedStateHandle 保留其数据
private fun File.saveTempFile() = bundleOf("path", absolutePath)
class TempFileViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
private var tempFile: File? = null
init {
savedStateHandle.setSavedStateProvider("temp_file") { // saveState()
if (tempFile != null) {
tempFile.saveTempFile()
} else {
Bundle()
}
}
}
fun createOrGetTempFile(): File {
return tempFile ?: File.createTempFile("temp", null).also {
tempFile = it
}
}
}
如需在用户返回时恢复 File 数据,请从 SavedStateHandle 中检索 temp_file Bundle。这正是 saveTempFile() 提供的包含绝对路径的 Bundle。该绝对路径随后可用于实例化新的 File。
private fun File.saveTempFile() = bundleOf("path", absolutePath)
private fun Bundle.restoreTempFile() = if (containsKey("path")) {
File(getString("path"))
} else {
null
}
class TempFileViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
private var tempFile: File? = null
init {
val tempFileBundle = savedStateHandle.get<Bundle>("temp_file")
if (tempFileBundle != null) {
tempFile = tempFileBundle.restoreTempFile()
}
savedStateHandle.setSavedStateProvider("temp_file") { // saveState()
if (tempFile != null) {
tempFile.saveTempFile()
} else {
Bundle()
}
}
}
fun createOrGetTempFile(): File {
return tempFile ?: File.createTempFile("temp", null).also {
tempFile = it
}
}
}
三、原理解析
先看一下其核心角色:
-
SavedStateRegistryOwner一个接口,用于标记其实现类(
Activity/Fragment)拥有着数据重建的能力,即作用是提供SavedStateRegistry对象。该接口主要实现类有Activity和Fragment。 -
SavedStateRegistryControllerSavedStateRegistry的控制类,用于创建SavedStatedRegistry,用于连接Activity/Fragment和SavedStateRegistry; -
SavedStateRegistry数据存储与恢复中心类
-
SaveStateProvider提供保存和恢复的数据。该接口只有一个
saveState方法,主要的作用将需要保存的数据用Bundle包装起来。 -
......
关于这些核心角色之间的关系,可参看下图:
SavedStateHandle的工作原理,简单总结为:
- 数据的保存是在
Activity的onSaveInstanceState()中调用了SavedStateRegistryController的performSave()方法来实现 SavedStateRegistryController是SavedStateRegistry的控制类,关于数据的保存和恢复都转发给了该类处理,performSave()方法最终最后转交到SavedStateRegistry的performSave()中。performSave()主要是将需要保存的数据写入到Activity的Bundle对象实现- 数据的恢复即在
onCreate()调用了performRestore()方法,将保存的数据取出恢复 - 对于需要保存的数据,实现
SavedStateProvider接口,注册一下需要保存的数据;取回数据时;外部通过使用和传给registerSavedStateProvider()方法时一样的key来取数据,并在取了之后将数据从mRestoredState中移除。 ViewModel创建时默认已经实现了SavedStateProvider等接口,实现了数据保存时从ViewModel中获取数据,恢复时给ViewModel赋值。- 存储的数据不能存超过1M
3.1 数据保存
SavedStateRegistryOwner用来提供SavedStateRegistry对象,其实现类拥有数据重建能力
public interface SavedStateRegistryOwner extends LifecycleOwner {
/**
* Returns owned {@link SavedStateRegistry}
*/
@NonNull
SavedStateRegistry getSavedStateRegistry();
}
以Activity为例,看一下ComponentActivity类
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
ContextAware,
LifecycleOwner,
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner,
ActivityResultRegistryOwner,
ActivityResultCaller {
final SavedStateRegistryController mSavedStateRegistryController =
SavedStateRegistryController.create(this);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
mSavedStateRegistryController.performRestore(savedInstanceState);
......
}
@CallSuper
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
......
mSavedStateRegistryController.performSave(outState);
mActivityResultRegistry.onSaveInstanceState(outState);
}
@NonNull
@Override
public final SavedStateRegistry getSavedStateRegistry() {
return mSavedStateRegistryController.getSavedStateRegistry();
}
......
}
ComponentActivity实现了SavedStateRegistryOwner接口,通过SavedStateRegistryController来创建SavedStateRegistry对象onCreate()方法中调用了SavedStateRegistryController的performRestore()方法,用于恢复已保存的数据onDestroy()方法中调用了SavedStateRegistryController的performSave()方法,用于保存数据。
SavedStateRegistryController类
SavedStateRegistryController是SavedStateRegistry的控制类,数据的保存和恢复都转发给了该类处理。
看一下其内部实现。
public final class SavedStateRegistryController {
private final SavedStateRegistryOwner mOwner;
private final SavedStateRegistry mRegistry;
private SavedStateRegistryController(SavedStateRegistryOwner owner) {
mOwner = owner;
mRegistry = new SavedStateRegistry();
}
@NonNull
public SavedStateRegistry getSavedStateRegistry() {
return mRegistry;
}
@MainThread
public void performRestore(@Nullable Bundle savedState) {
Lifecycle lifecycle = mOwner.getLifecycle();
//必须在 Activity 的 onCreate 方法调用结束前进行数据恢复
if (lifecycle.getCurrentState() != Lifecycle.State.INITIALIZED) {
throw new IllegalStateException("Restarter must be created only during "
+ "owner's initialization stage");
}
lifecycle.addObserver(new Recreator(mOwner));
mRegistry.performRestore(lifecycle, savedState);
}
@MainThread
public void performSave(@NonNull Bundle outBundle) {
mRegistry.performSave(outBundle);
}
@NonNull
public static SavedStateRegistryController create(@NonNull SavedStateRegistryOwner owner) {
return new SavedStateRegistryController(owner);
}
}
SavedStateRegistryController最终将数据的保存和恢复转交给SavedStateRegistry的同名方法实现。
数据的保存是在Activity的onSaveInstanceState()中调用了SavedStateRegistryController的performSave()方法,最后转交到SavedStateRegistry的performSave()中。
SavedStateRegistry类
看一下SavedStateRegistry类的performSave()实现
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;
@MainThread
void performSave(@NonNull Bundle outBundle) {
Bundle components = new Bundle();
//mRestoredState不为空,表示之前恢复的数据还没有被消费完,需要将没有消费的数据再一次保存。
if (mRestoredState != null) {
components.putAll(mRestoredState);
}
//遍历所有注册的SavedStateProvider,将所有的SavedStateProvider提供的数据保存起来。即把所有需要保存的Bundle通过outBundle保存起来
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());
}
//将所有保存的数据全部写入到Activity的Bundle对象
outBundle.putBundle(SAVED_COMPONENTS_KEY, components);
}
......
public interface SavedStateProvider {
@NonNull
Bundle saveState();//将需要保存的数据用Bundle包装起
}
}
performSave()的主要内容:
- 判断是否存在上一次恢复的数据,如果存在将其添加保存;
- 将所有需要保存的
Bundle保存起来; - 将所有保存的数据写入到
Activity的Bundle对象
小结:
- 数据的保存是在
Activity的onSaveInstanceState()中调用了SavedStateRegistryController的performSave()方法来实现 SavedStateRegistryController是SavedStateRegistry的控制类,关于数据的保存和恢复都转发给了该类处理,performSave()方法最终最后转交到SavedStateRegistry的performSave()中。performSave()主要是将需要保存的数据写入到Activity的Bundle对象实现
3.2 数据恢复
关于数据恢复,直接看一下SavedStateRegistry的performRestore()
@MainThread
void performRestore(@NonNull Lifecycle lifecycle, @Nullable Bundle savedState) {
//已恢复过,只能恢复一次
if (mRestored) {
throw new IllegalStateException("SavedStateRegistry was already restored.");
}
//待恢复数据不为空,将其取出
if (savedState != null) {
mRestoredState = savedState.getBundle(SAVED_COMPONENTS_KEY);
}
//通过监听 Lifecycle 来确定当前是否处于可以恢复数据的生命周期阶段,用一个布尔变量 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;
}
小结:
数据恢复即在onCreate()调用了performRestore()方法,将保存的数据取出恢复
3.3 数据入口与消费
数据保存时是如何从ViewModel中获取数据的?数据恢复时又是如何给ViewModel赋值的?
数据保存入口
数据保存时,有需要保存的数据需要添加到SafeIterableMap<String, SavedStateProvider> mComponents中,SavedStateRegistry提供了一个入口方法registerSavedStateProvider()。
外部需要实现 SavedStateProvider 接口,在 saveState()返回想要保存的数据,然后调用registerSavedStateProvider 方法将 SavedStateProvider 对象提交给 SavedStateRegistry。
@MainThread
public void registerSavedStateProvider(@NonNull String key,
@NonNull SavedStateProvider provider) {
//注册想要保存的数据,等到 performSave再保存。外部通过一个唯一标识 key 来和要保存的数据 Bundle 相对应,
SavedStateProvider previous = mComponents.putIfAbsent(key, provider);
if (previous != null) {
throw new IllegalArgumentException("SavedStateProvider with the given key is"
+ " already registered");
}
}
想要通过SavedStateRegistry保存数据,只需要实现SavedStateProvider接口,注册一下就可以了;取回数据时,通过原来的key取回即可。
数据消费入口
数据消费,即需要开发者通过取键值对的方式来消费数据,将用户数据或者 UI 状态恢复到销毁前的状态。
消费数据的入口就是 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;
}
外部通过使用和传给 registerSavedStateProvider() 方法时一样的 key 来取数据,并在数据获取后将数据从 mRestoredState 中移除。
如果所有数据都被消费了的话,那么就将 mRestoredState 置为 null,标记着所有数据都已经被消费完了
3.4 入口函数调用
看一下何处调用了registerSavedStateProvider() 和 consumeRestoredStateForKey()
Activity与Fragment默认实现了HasDefaultViewModelProviderFactory接口,默认返回SavedStateViewModelFactory,看一下其内部如何创建ViewModel实例。
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
//判断viewmodel 是否为 AndroidViewModel的子类
boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
Constructor<T> constructor;
if (isAndroidViewModel && mApplication != null) {
//是AndroidViewModel的子类,尝试查找它是否拥有(Application,SavedStateHandle)两个参数的构造函数
constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
} else {
//查找它是否拥有(SavedStateHandle)一个参数的构造函数
constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
}
// doesn't need SavedStateHandle
if (constructor == null) {
//上面两种方式都没找到,使用AndroidViewModelFactory创建viewmodel实例。可以无参数,也可以携带一个(Application)参数
return mFactory.create(modelClass);
}
//构建出SavedStateHandleController对象
SavedStateHandleController controller = SavedStateHandleController.create(
mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
try {
T viewmodel;
if (isAndroidViewModel && mApplication != null) {
//反射构造ViewModel实例对象的时候,把参数一同传递了进去。
viewmodel = constructor.newInstance(mApplication, controller.getHandle());
} else {
viewmodel = constructor.newInstance(controller.getHandle());
}
viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
//返回新创建的ViewModel实例对象
return viewmodel;
}
......
}
SavedStateViewModelFactory的create()方法主要内容为:
- 判断需要创建的
ViewModel是否是AndroidViewModel子类 - 判断
ViewModel是否拥有参数SavedStateHandle的构造器。如果没有,使用AndroidViewModelFactory创建viewmodel实例;如果有,构建SavedStateHandleController对象 - 反射构造
ViewModel实例对象。
SavedStateHandleController类
看一下SavedStateHandleController的create()方法
static SavedStateHandleController create(SavedStateRegistry registry, Lifecycle lifecycle,
String key, Bundle defaultArgs) {
//从数据中心SavedStateRegistry获取该ViewModel的Bundle数据对象
Bundle restoredState = registry.consumeRestoredStateForKey(key);
//构建SavedStateHandle对象,并把restoredState中的数据再拆分出来,存储到mRegular这个 map集合
SavedStateHandle handle = SavedStateHandle.createHandle(restoredState, defaultArgs);
//构建SavedStateHandleController对象
SavedStateHandleController controller = new SavedStateHandleController(key, handle);
//把SavedStateHandle的需要保存的数据注册到了SavedStateRegistry中
controller.attachToLifecycle(registry, lifecycle);
tryToAddRecreator(registry, lifecycle);
return controller;
}
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());
}
SavedStateHandleController的create()方法的主要内容:
- 获取数据缓存;
- 构建
SavedStateHandle对象,对数据缓存进行拆分,存储; - 构建
SavedStateHandleController对象,把SavedStateHandle的需要保存的数据注册到了SavedStateRegistry中。
其中:
SavedStateHandleController中的key就是ViewModel的key;defaultArgs对于Activity而言就是getIntent().getExtras(),对于Fragment而言就是getArguments()
3.5 getLiveData
前述示例通过 SavedStateHandle.getLiveData方法来生成一个 LiveData 对象来存放持久化存放的数据。
看一下SavedStateHandle类
public final class SavedStateHandle {
final Map<String, Object> mRegular;
final Map<String, SavedStateProvider> mSavedStateProviders = new HashMap<>();
private final Map<String, SavingStateLiveData<?>> mLiveDatas = new HashMap<>();
public SavedStateHandle(@NonNull Map<String, Object> initialState) {
mRegular = new HashMap<>(initialState);
}
public SavedStateHandle() {
mRegular = new HashMap<>();
}
@MainThread
public boolean contains(@NonNull String key) {
return mRegular.containsKey(key);
}
@MainThread
@NonNull
public <T> MutableLiveData<T> getLiveData(@NonNull String key) {
return getLiveDataInternal(key, false, null);
}
@MainThread
@Nullable
public <T> T get(@NonNull String key) {
return (T) mRegular.get(key);
}
......
}
SavedStateHandle 包含两个构造函数
initialState中保存的即是Activity重建时保留下来的的键值对数据mRegular中保存的即是最终要持久化保存的键值对数据
如果调用的有参构造函数,则代表着此次初始化是 Activity 被销毁重建的情况;如果调用的是无参构造函数,则代表着此次初始化是 Activity 全新启动的情况
看一下SavedStateHandle中的getLiveData方法
@MainThread
@NonNull
public <T> MutableLiveData<T> getLiveData(@NonNull String key) {
return getLiveDataInternal(key, false, null);
}
@MainThread
@NonNull
public <T> MutableLiveData<T> getLiveData(@NonNull String key,
@SuppressLint("UnknownNullness") T initialValue) {
return getLiveDataInternal(key, true, initialValue);
}
@NonNull
private <T> MutableLiveData<T> getLiveDataInternal(
@NonNull String key,
boolean hasInitialValue,
@Nullable T initialValue) {
MutableLiveData<T> liveData = (MutableLiveData<T>) mLiveDatas.get(key);
if (liveData != null) {
return liveData;
}
SavingStateLiveData<T> mutableLd;
// double hashing but null is valid value
if (mRegular.containsKey(key)) {
mutableLd = new SavingStateLiveData<>(this, key, (T) mRegular.get(key));
} else if (hasInitialValue) {
mutableLd = new SavingStateLiveData<>(this, key, initialValue);
} else {
mutableLd = new SavingStateLiveData<>(this, key);
}
mLiveDatas.put(key, mutableLd);
return mutableLd;
}
getLiveData()方法的主要内容:
返回一个和 key 还有 mRegular关联的 LiveData 对象。LiveData 对象的初始默认值会从mRegular和initialValue两个之间选取,每次生成的 LiveData 对象也都会被保存在 mLiveDatas 中,以便后续复用
SavingStateLiveData类
当外部对 LiveData 进行值更新操作时,SavedStateHandle 需要拿到最新值,因为最终持久化保存的肯定也需要是最新值。
getLiveDataInternal方法返回的 SavingStateLiveData 对象会在 setValue 方法被调用后,同步更新 mRegular 中的键值对数据。
static class SavingStateLiveData<T> extends MutableLiveData<T> {
private String mKey;
private SavedStateHandle mHandle;
@Override
public void setValue(T value) {
if (mHandle != null) {
//同步更新mRegular中键值对
mHandle.mRegular.put(mKey, value);
}
super.setValue(value);
}
void detach() {
mHandle = null;
}
......
}
setSavedStateProvider 方法
SavedStateHandle 开放了一个 setSavedStateProvider 方法交由外部来传入 SavedStateProvider 对象,外部负责实现 saveState()方法来返回想要持久化缓存的 Bundle 对象,由 SavedStateHandle 来负责调用该方法
@MainThread
public void setSavedStateProvider(@NonNull String key, @NonNull SavedStateProvider provider) {
mSavedStateProviders.put(key, provider);
}
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<String, SavedStateProvider> map = new HashMap<>(mSavedStateProviders);
for (Map.Entry<String, SavedStateProvider> entry : map.entrySet()) {
Bundle savedState = entry.getValue().saveState();
set(entry.getKey(), savedState);
}
// Convert the Map of current values into a Bundle
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();
// "parcelable" arraylists - lol
res.putParcelableArrayList("keys", keys);
res.putParcelableArrayList("values", value);
return res;
}
};
SavedStateHandle原理总结:
- 数据的保存是在
Activity的onSaveInstanceState()中调用了SavedStateRegistryController的performSave()方法来实现 SavedStateRegistryController是SavedStateRegistry的控制类,关于数据的保存和恢复都转发给了该类处理,performSave()方法最终最后转交到SavedStateRegistry的performSave()中。performSave()主要是将需要保存的数据写入到Activity的Bundle对象实现- 数据的恢复即在
onCreate()调用了performRestore()方法,将保存的数据取出恢复 - 对于需要保存的数据,实现
SavedStateProvider接口,注册一下需要保存的数据;取回数据时;外部通过使用和传给registerSavedStateProvider()方法时一样的key来取数据,并在取了之后将数据从mRestoredState中移除。 ViewModel创建时默认已经实现了SavedStateProvider等接口,实现了数据保存时从ViewModel中获取数据,恢复时给ViewModel赋值。- 存储的数据不能存超过1M