SavedStateHandle组件解析

3,322 阅读13分钟

一、为什么使用SavedStateHandle

Activity被意外销毁的情况有两种

  1. 资源配置变更导致Activity销毁,例如屏幕旋转
  2. 系统资源限制导致Activity被销毁

ViewModel可以解决第一种情况下的数据恢复问题,但是对于第二种,则需要依赖原生提供的数据保护与恢复机制,即onSaveInstanceState(Bundle)onRestoreInstanceState(Bundle)

onSaveInstanceState(Bundle) 方法保存的数据在资源配置更改或 Activity 被意外杀死时都会被保留,但存在存储容量和存取速度的限制。因为 Bundle 有着容量限制,不适合用于存储大量数据,且 onSaveInstanceState(Bundle) 方法会将数据序列化到磁盘,如果要保存的数据很复杂,序列化会消耗大量的内存和时间。

所以 onSaveInstanceState(Bundle) 仅适合用于存储少量的简单类型的数据

对于Activity的第二种销毁情况,数据的保存和恢复被限制在Activity 的特定方法里,无法直接在ViewModel中决定哪些数据需要保留,也无法直接拿到恢复后的数据。

SavedStateHandle组件可以看作是ViewModel功能的扩展,解决ViewModel无法感知onSaveInstanceState被触发的问题

二、基本使用

2.1 简单使用

SavedStateHandle的使用流程一般为:

  1. SavedStateHandle 作为 ViewModel 的构造参数
  2. ViewModel 内部通过 SavedStateHandle.getLiveData方法来生成一个 LiveData 对象,LiveData 中的数据即我们想要持久化保存的数据。如果是全新启动 ActivityLiveData 中保存的值为 null;如果是重建后的 ActivityLiveData 中保存的值则为重建前其自身的值
  3. 传给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 中的数据将作为BundleActivityFragmentonSaveInstanceState(Bundle)其余部分一起保存和恢复。

直接支持类型

默认情况下,您可以对 SavedStateHandle 调用 set()get(),以处理与 Bundle 相同的数据类型

类型/类支持数组支持
doubledouble[]
intint[]
longlong[]
StringString[]
bytebyte[]
charchar[]
CharSequenceCharSequence[]
floatfloat[]
ParcelableParcelable[]
SerializableSerializable[]
shortshort[]
SparseArray
Binder
Bundle
ArrayList
Size (only in API 21+)
SizeF (only in API 21+)

如果该类没有扩展上述列表中的任何一项,可考虑通过@Parcelize kotlin注解或直接实现Parcelable来使该类变为Parcelable类型。

保存非Parcelable

如果某个类未实现 ParcelableSerializable 且不能修改为实现这些接口之一,则无法直接将该类的实例保存到 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的工作原理,简单总结为:

  1. 数据的保存是在ActivityonSaveInstanceState()中调用了SavedStateRegistryControllerperformSave()方法来实现
  2. SavedStateRegistryControllerSavedStateRegistry的控制类,关于数据的保存和恢复都转发给了该类处理,performSave()方法最终最后转交到SavedStateRegistryperformSave()中。
  3. performSave()主要是将需要保存的数据写入到ActivityBundle对象实现
  4. 数据的恢复即在onCreate()调用了performRestore()方法,将保存的数据取出恢复
  5. 对于需要保存的数据,实现SavedStateProvider接口,注册一下需要保存的数据;取回数据时;外部通过使用和传给 registerSavedStateProvider() 方法时一样的 key 来取数据,并在取了之后将数据从 mRestoredState 中移除。
  6. ViewModel创建时默认已经实现了SavedStateProvider等接口,实现了数据保存时从ViewModel中获取数据,恢复时给ViewModel赋值。
  7. 存储的数据不能存超过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();
    }
    ......
}
  1. ComponentActivity实现了SavedStateRegistryOwner接口,通过SavedStateRegistryController来创建SavedStateRegistry对象
  2. onCreate()方法中调用了SavedStateRegistryControllerperformRestore()方法,用于恢复已保存的数据
  3. onDestroy()方法中调用了SavedStateRegistryControllerperformSave()方法,用于保存数据。

SavedStateRegistryController

SavedStateRegistryControllerSavedStateRegistry的控制类,数据的保存和恢复都转发给了该类处理。

看一下其内部实现。

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的同名方法实现。

数据的保存是在ActivityonSaveInstanceState()中调用了SavedStateRegistryControllerperformSave()方法,最后转交到SavedStateRegistryperformSave()中。

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()的主要内容:

  1. 判断是否存在上一次恢复的数据,如果存在将其添加保存;
  2. 将所有需要保存的Bundle保存起来;
  3. 将所有保存的数据写入到ActivityBundle对象

小结

  1. 数据的保存是在ActivityonSaveInstanceState()中调用了SavedStateRegistryControllerperformSave()方法来实现
  2. SavedStateRegistryControllerSavedStateRegistry的控制类,关于数据的保存和恢复都转发给了该类处理,performSave()方法最终最后转交到SavedStateRegistryperformSave()中。
  3. performSave()主要是将需要保存的数据写入到ActivityBundle对象实现

3.2 数据恢复

关于数据恢复,直接看一下SavedStateRegistryperformRestore()

@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()

ActivityFragment默认实现了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;
    }
    ......
}

SavedStateViewModelFactorycreate()方法主要内容为

  1. 判断需要创建的ViewModel是否是AndroidViewModel子类
  2. 判断ViewModel是否拥有参数SavedStateHandle的构造器。如果没有,使用AndroidViewModelFactory创建viewmodel实例;如果有,构建SavedStateHandleController对象
  3. 反射构造ViewModel实例对象。

SavedStateHandleController

看一下SavedStateHandleControllercreate()方法

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

SavedStateHandleControllercreate()方法的主要内容

  1. 获取数据缓存;
  2. 构建SavedStateHandle对象,对数据缓存进行拆分,存储;
  3. 构建SavedStateHandleController对象,把SavedStateHandle的需要保存的数据注册到了SavedStateRegistry中。

其中:

  1. SavedStateHandleController中的key就是ViewModelkey
  2. 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 包含两个构造函数

  1. initialState 中保存的即是 Activity 重建时保留下来的的键值对数据
  2. 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 对象的初始默认值会从mRegularinitialValue两个之间选取,每次生成的 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原理总结

  1. 数据的保存是在ActivityonSaveInstanceState()中调用了SavedStateRegistryControllerperformSave()方法来实现
  2. SavedStateRegistryControllerSavedStateRegistry的控制类,关于数据的保存和恢复都转发给了该类处理,performSave()方法最终最后转交到SavedStateRegistryperformSave()中。
  3. performSave()主要是将需要保存的数据写入到ActivityBundle对象实现
  4. 数据的恢复即在onCreate()调用了performRestore()方法,将保存的数据取出恢复
  5. 对于需要保存的数据,实现SavedStateProvider接口,注册一下需要保存的数据;取回数据时;外部通过使用和传给 registerSavedStateProvider() 方法时一样的 key 来取数据,并在取了之后将数据从 mRestoredState 中移除。
  6. ViewModel创建时默认已经实现了SavedStateProvider等接口,实现了数据保存时从ViewModel中获取数据,恢复时给ViewModel赋值。
  7. 存储的数据不能存超过1M