一、为什么使用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。 -
SavedStateRegistryController
SavedStateRegistry
的控制类,用于创建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