萌萌の初音
萌萌の初音
发布于 2022-05-19 / 1371 阅读
0

SavedStateHandle的简单使用

1. SavedStateHandle简介

SavedStateHandle搭配ViewModel作为状态保存使用,ViewModel虽然也保存了状态,但仅限于屏幕旋转等资源配置变更导致Activity和Fragment销毁,如果是系统kill导致的销毁无法还原,SavedStateHandle就可以对ViewModel里的数据进行还原。

2. SavedStateHandle的简单使用

1. 依赖的引入

ext {
    lifecycle_version = "2.4.1"
}

dependencies {
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
}

2. ViewModel绑定SavedStateHandle

ViewModel:

class MyViewModel(private val savedStateHandle: SavedStateHandle): ViewModel()

AndroidViewModel:

class MyViewModel(private val application: Application, private val savedStateHandle: SavedStateHandle): AndroidViewModel(application)

带SavedStateHandle的ViewModel有专门的工厂类进行实现(SavedStateViewModelFactory),我们只需要把相应的构造参数按照以上方法进行书写即可,需要使用application就用AndroidViewModel。

3. SavedStateViewModelFactory

public SavedStateViewModelFactory(@Nullable Application application,
            @NonNull SavedStateRegistryOwner owner)

在工厂构造方法中,我们需要传入Activity和Fragment的LifecycleOwner, Application可传可不传,但如果在第二步中你用的AndroidViewModel就需要传入。

    @Override
    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);
        }
        // doesn't need SavedStateHandle
        if (constructor == null) {
            return mFactory.create(modelClass);
        }

        SavedStateHandleController controller = SavedStateHandleController.create(
                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
        try {
            T viewmodel;
            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方法中通过isAndroidViewModel 和 mApplication != null来判断如何对ViewModel进行初始化,所以第二步需要固定构造参数。如果有特殊需求可以copy源码对工厂类进行重写。

4. 在Activity和Fragment中初始化

viewModel = ViewModelProvider(this, SavedStateViewModelFactory(application, this)).get(MyViewModel::class.java)

以上步骤就可以初始化一个带有SavedStateHandle的ViewModel了。

5. SavedStateHandle在ViewModel中的使用

SavedStateHandle可以缓存LiveData、也可缓存普通的数据;除了常用的List、String、Int等,其他实体需要接入Serializable或者注解@Parcelize实现序列化Parcelable,否则在应用销毁时缓存数据报错。

SavedStateHandle.getLiveData<String>("key")
SavedStateHandle.get<String?>("key")

缓存非序列化的类、实体,我们可以使用setSavedStateProvider方法返回Bundle实现。

savedStateHandle.setSavedStateProvider("key") {
    if (file != null) {
        file
   } else {
        Bundle()
    }
}

以上就是SavedStateHandle的简单使用。