ViewModel使用以及源码分析(二)-SavedState

前言

ViewModel使用以及源码分析(一)中,我们留了一个小尾巴SavedStateHandle没有讲解,这部分设计的内容比较多,本篇开始讲解。
主要就是涉及到保存的一些知识。

1. 概念

1.1 Activity 的重建

我们知道,Activity 被意外销毁的情况可以分为两种:

  1. 由于屏幕旋转等配置更改的原因导致 Activity 被销毁
  2. 由于系统资源限制导致 Activity 被销毁

对于以上两种情况,我们当然希望 Activity 重建时之前加载的数据以及用户状态都能够得到恢复,每种情况目前都有着不同的恢复方法

  1. 对于第一种情况,Jetpack 提供了 ViewModel 这个组件来解决这个问题。ViewModel 可以在屏幕旋转后继续存留,适合用于在内存中存储比较复杂或者量比较大的数据,例如:用 RecyclerView 加载的多个列表项对应的 Data。但当第二种情况发生时 ViewModel 是无法被保留下来的,此后当用户重新回到 Activity 时,只会得到一个全新的 ViewModel 实例并且也需要重新加载列表数据。

  2. 对于第二种情况,需要依赖于 Activity 原生提供的数据保存及恢复机制,即依赖以下两个方法来实现数据的保存和恢复逻辑。onSaveInstanceState(Bundle) 方法保存的数据在配置更改和 Activity 被意外杀死时都会被保留,但也有着存储容量和存取速度的限制。因为 Bundle 有着容量限制,不适合用于存储大量数据,且 onSaveInstanceState(Bundle) 方法会将数据序列化到磁盘,如果要保存的数据很复杂,序列化会消耗大量的内存和时间。所以 onSaveInstanceState(Bundle) 仅适合用于存储少量的简单类型的数据

    • onSaveInstanceState(Bundle)。用于保存数据
    • onCreate(Bundle?) 或者 onRestoreInstanceState(Bundle)。用于恢复数据

Google 官方也对这两种情况进行了对比:
在这里插入图片描述
对于第二种情况,因为数据的保存和恢复流程被限制在了 Activity 的特定方法里,我们无法直接在 ViewModel 中决定哪些数据需要被保留,也无法直接拿到恢复后的数据,使得整个重建流程和 ViewModel 分裂开了

为了解决这个问题,Jetpack 提供了 SavedStateHandle 这么一个组件,可以看做是对 ViewModel 的功能扩展,使得开发者可以直接在 ViewModel 中直接操作整个数据的重建过程

1.2 SavedState 概念

SavedState 是为了弥补 ViewModel 无法直接感知 onSaveInstanceState 被触发的时机的缺陷而产生的。
在这里插入图片描述

在页面即将被销毁的时候,每个使用 SavedState 的 ViewModel 都会创建一个 Bundle 来存储自己的这份数据,最后这些 Bundle 会被汇总到一个 Bundle 中,然后再保存到 onSaveInstanceState(Bundle outState) 的 outState 中;

当页面恢复的时候,会从 onCreate(Bundle savedInstanceState) 中的 savedInstanceState 中取出原来存放的总的那个 Bundle,然后再取出一个个的属于 ViewModel 的子 Bundle,从而实现在 ViewModel 中复用之前存储的数据;
其实就是利用 Bundle 可以保存另一个 Bundle 这么一个特点,分层分区保存数据,让数据之间相互分离,进而方便整存整取;

2. 使用实例

2.1ViewModel 搭配 SavedState 实现数据复用

核心思想
当 Activity 的 onSaveInstanceState 方法被执行的时候,会触发 SavedStateHandle 的 Bundle saveState() 方法,从而保存其数据;当 Activity 被恢复的时候,在新建 ViewModel 实例对象的时候,会从 Activity 的 savedInstanceState 中提取之前存储数据,然后构造 SavedStateHandle 对象并把恢复的数据赋值给该对象,随后把 SavedStateHandle 传递到 ViewModel 中,从而复用其数据;

class SavedStateViewModel extends ViewModel {
   
    // 需要引用 SavedStateHandle
    private SavedStateHandle mHandle;
 
    public SavedStateViewModel(SavedStateHandle handle) {
   
        mHandle = handle;
        // 实现数据的恢复
        Object text = mHandle.get("text");
        if (null == text) {
   
            String time = String.valueOf(System.currentTimeMillis() / 1000);
            // 实现数据的保存
            mHandle.set("text", time);
            Log.e("SavedStateViewModel 初始化数据 = " + time);
        } else {
   
            Log.e("SavedStateViewModel 恢复数据 = " + text);
        }
    }
}
 
// ViewModelActivity.java
class AcaActivity extends AppCompatActivity {
   
    SavedStateViewModel mSavedStateViewModel;
    void onCreate(Bundle savedInstanceState) {
   
        // 这边创建时传入了 SavedStateViewModelFactory
        mSavedStateViewModel = new ViewModelProvider(this).get(SavedStateViewModel.class);
        Log.e("mSavedStateViewModel hashCode = " + mSavedStateViewModel.hashCode());
    }
}

ViewModel使用以及源码分析(一)中,构造了一个UserViewModel类,参数只有application

public UserViewModel(@NonNull Application application) {
   }

这里是构造了一个带SavedStateHandle参数的ViewModel类,所以用户可以构造四种ViewModel类。

1. public UserViewModel() {
   }
2. public UserViewModel(@NonNull Application application) {
   }
3. public UserViewModel(SavedStateHandle handle) {
   }
4. public UserViewModel(@NonNull Application application, SavedStateHandle handle) {
   }

3. 源码分析

我们先来看一下SavedState components里面几个组件,分别是:

  • SavedStateRegistryOwner
  • SavedStateRegistryController
  • SavedStateRegistry
  • SavedStateProvider。
  • SavedStateHandle

一下子怼上来5个不明所以的类,我猜测大家多多少少都有点懵B。在这里我先分别看5个类的作用:

  • SavedStateRegistryOwner:一个接口,有一个getSavedStateRegistry 方法,作用是提供SavedStateRegistry对象。该接口主要实现类有Activity和Fragment。

  • SavedStateRegistryController:SavedStateRegistry的控制类,主要有两个方法:performRestore方法的作用恢复数据;performSave方法主要保存数据。Activity和Fragment直接操作类就是该类。

  • SavedStateRegistry: 主要是从UI控制器(Activity或者Fragment等)恢复数据,或者将需要保存的数据写入UI控制器的Bundle里面;外部可以通过registerSavedStateProvider方法注册SavedStateProvider,这样SavedStateRegistry在保存数据会SavedStateProvider提供的数据。SavedStateRegistryController主要操作类就是该类。

  • SavedStateProvider: 主要是提供保存和恢复的数据。该接口只有一个saveState方法,主要的作用将需要保存的数据用Bundle包装起来。

  • SavedStateHandle:SavedStateRegistry 封装了 Activity 层次进行存数据和恢复数据的逻辑,恢复后的数据也需要转交给 SavedStateHandle。
    因为 SavedStateHandle 是作为 ViewModel 的构造参数来使用的,我们在 ViewMode 中能直接接触到的都是 SavedStateHandle。

可以用一张图来描述他们之间的关系:
在这里插入图片描述

3.1 SavedState 相关源码分析

SavedState 涉及的类结构图及其中的组成成员
在这里插入图片描述
SavedStateRegistry 模型图示
一个总 Bundle ,以 key-value 形式存储着每个 ViewModel 对应的子 Bundle;
在这里插入图片描述
SavedState 数据存储流程
在这里插入图片描述

3.2 ComponentActivity

无论是SavedStateHandle还是其他类,都在Activity里面集中,一切都得从最重要的ComponentActivity讲起。大局观毕竟是最重要的。

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner,
        ActivityResultRegistryOwner,
        ActivityResultCaller {
   }

ViewModel使用以及源码分析(一)中我们讲解了实现ViewModelStoreOwner和HasDefaultViewModelProviderFactory的代码。这里还要继续讲解这个SavedStateRegistryOwner接口,听名字就知道干什么用的,保存状态的。

public interface SavedStateRegistryOwner extends LifecycleOwner {
   
    @NonNull
    SavedStateRegistry getSavedStateRegistry();
}

接口就一个方法,看一下ComponentActivity里面的实现

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

实现方法就是调用了mSavedStateRegistryController的getSavedStateRegistry方法,这个mSavedStateRegistryController就是Activity的变量。马上分析~~

分析Activity总是要分析一下onCreate,继续看一下

@Override
private final SavedStateRegistryController mSavedStateRegistryController =
        SavedStateRegistryController.create(this);

private ActivityResultRegistry mActivityResultRegistry = new ActivityResultRegistry() {
   ...}

protected void onCreate
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值