ViewModel的使用和源码分析

24 阅读10分钟

ViewModel 概述

ViewModel 是一个状态存储器,它的主要优势是可以缓存状态,让 ViewModel 中的数据不受 Configuration Change 的影响。这意味着当你切换页面,或者屏幕旋转的时候,不需要重新获取数据。

ViewModel 的优势

我们先来看看屏幕旋转时遇到的问题,如果在 AndroidManifest.xml 中没有配置configChanges="orientation|screenSize" ,系统会销毁并重建 Activity ,我们一般使用 onSaveInstanceState() 方法保存数据,然后使用 onCreate() 中的 Bundle 恢复数据。但是这个方法只能恢复序列化的数据,如果要序列化的对象很复杂,序列化会占用大量内存。由于这个过程发生在主线程,耗时的序列化可能导致掉帧和页面卡顿,并且这个方法不能用于恢复 Bitmap 这种大容量的数据( IPC 对 Bundle 有 1M 的限制)。

使用 ViewModel 可以解决这个问题, ViewModel 可以缓存数据,不受 Configuration Change 的影响。 ViewModel 的优势主要有 2 个:

  • 更便于保存数据
  • 更方便 UI 组件之间的通信

更便于保存数据

我们通常在 Activity 的 onCreate() 方法中请求 ViewModel ,在旋转设备屏幕时,系统会多次调用 onCreate() 方法,而 ViewModel 从你首次请求 ViewModel 直到 Activity 执行 onDestroy() 方法期间一直存在。如下图左侧展示了旋转屏幕到最终退出页面,Activity 经历的多个生命周期状态,右侧是对应 ViewModel 的生命周期:

image.png

Activity 销毁后, ViewModel 的 onCleared() 方法才会最终执行释放 ViewModel 。它不会像 Activity 那样反复重建,从而节省了用于状态维护(数据的存储和获取、序列化和反序列化)的代码。

ViewModel 在其生命周期内类似一个单例,这就引出了一个更好用的特性,那就是 UI 组件间的通信。

更方便UI组件之间的通信

由于 Activity 销毁后,ViewModel 中的资源才会释放,就可以很方便地运用在一个 Activity 中有多个 Fragment 共享数据的场景,多个 Fragment 可以持有同一个 ViewModel 的实例,再结合 LiveData ,这也就意味着数据状态的共享

比如下面这个示例:

public class MyActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
    }
}

activity_my.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/fragment_list"
        android:name="com.example.test.viewmodel.ListFragment"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <fragment
	     android:id="@+id/fragment_detail"
        android:name="com.example.test.viewmodel.DetailFragment"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toEndOf="@+id/fragment_list"
        app:layout_constraintTop_toTopOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

ShareViewModel 用于共享数据:

public class ShareViewModel extends ViewModel {

    private MutableLiveData<String> selected = new MutableLiveData<>();

    public void setSelectedItem(String item){
        selected.setValue(item);
    }

    public LiveData<String> getSelectedLiveData() {
        return selected;
    }
}

ListFragment用于展示列表:

public class ListFragment extends Fragment {
    private ShareViewModel shareViewModel;
    private List<String> list = new ArrayList<>();
    private RecyclerView.Adapter adapter;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_list, container, false);
        RecyclerView recyclerView = view.findViewById(R.id.rv);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this.getContext());
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);

        adapter = new RecyclerView.Adapter<ItemViewHolder>() {
            @NonNull
            @Override
            public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
                return new ItemViewHolder(new TextView(parent.getContext()));
            }

            @Override
            public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) {
                String s = list.get(position);
                if (holder.itemView instanceof TextView) {
                    ((TextView) holder.itemView).setText(s);
                    // item 被点击后通知 shareViewModel
                    (holder.itemView).setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            shareViewModel.setSelectedItem(s);
                        }
                    });
                }
            }

            @Override
            public int getItemCount() {
                return list.size();
            }
        };
        recyclerView.setAdapter(adapter);

        for (int i = 0; i < 100; i++) {
            list.add("item " + i);
        }
        adapter.notifyDataSetChanged();
        return view;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        shareViewModel = new ViewModelProvider(requireActivity()).get(ShareViewModel.class);
    }

    static class ItemViewHolder extends RecyclerView.ViewHolder {
        TextView tv;

        public ItemViewHolder(@NonNull TextView itemView) {
            super(itemView);
            tv = itemView;
        }
    }
}

DetailFragment用于展示详情页:

public class DetailFragment extends Fragment {

    private ShareViewModel shareViewModel;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_detail, container, false);
        TextView tv = view.findViewById(R.id.tv);

        // 观察被点击的项,收到通知后更新
        shareViewModel.getSelectedLiveData().observe(getViewLifecycleOwner(), new Observer<String>() {
            @Override
            public void onChanged(String s) {
                tv.setText(s);
            }
        });
        return view;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        shareViewModel = new ViewModelProvider(requireActivity()).get(ShareViewModel.class);
    }
}

ListFragment 和 DetailFragment 的 requireActivity() 方法返回的是同一个宿主 Activity ,因此两个 Fragment 之间返回的是同一个 ViewModel 。再结合 LiveData ,把 LiveData 放到 ViewModel 中,这样在 ListFragment 中点击了某个 item , DetailFragment 马上就可以监听到并显示相应的字符串,如下图所示:

image.png

源码分析

ViewModel 的核心就是因配置更改,系统重建 Activity 或 Fragment 后,ViewModel 的实例仍然存在,这是怎么实现的呢?下面我们就通过源码来进行分析。

自定义 ViewModel 需要继承 ViewModel 类,我们先来看看 ViewModel 类的代码:

public abstract class ViewModel {

    private volatile boolean mCleared = false;

    // clear() 方法中会调用 onCleared() ,当 ViewModel 观察了一些数据,可以使用这个方法
    // 清除订阅来避免 ViewModel 的内存泄露
    protected void onCleared() {
    }

    @MainThread
    final void clear() {
        mCleared = true;
        ...
        onCleared();
    }
}

ViewModel 类是一个抽象类,内部逻辑比较简单。 onCleared() 方法是一个空方法,可以重写这个方法清除订阅来避免 ViewModel 的内存泄露

前面的代码中,通过new ViewModelProvider(requireActivity()).get(ShareViewModel.class)可以获取到 ShareViewModel 的实例,先来看看ViewModelProvider(requireActivity())

public class ViewModelProvider {

    private final Factory mFactory;

    private final ViewModelStore mViewModelStore;

    // 一个参数 ViewModelStoreOwner
    public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }


    public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
        this(owner.getViewModelStore(), factory);
    }


    public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }

}

可以看到 ViewModelProvider 的构造函数传入的参数是 ViewModelStoreOwner,它是一个接口:

public interface ViewModelStoreOwner {

    @NonNull
    ViewModelStore getViewModelStore();
}

在 ComponentActivity 中对这个接口进行了实现:

public class ComponentActivity implements ViewModelStoreOwner {

    private ViewModelStore mViewModelStore;

    public ViewModelStore getViewModelStore() {
        if (getApplication() == null) {
            throw new IllegalStateException("Your activity is not yet attached to the "
                    + "Application instance. You can't request ViewModel before onCreate call.");
        }
        ensureViewModelStore();
        return mViewModelStore;
    }

}

类似自定义 View ,创建 ViewModelProvider 实例最终都会调用 ViewModelProvider 类的第 3 个构造方法,其中 ViewModelStore 为 ViewModel 的存储器,Factory 为创建 ViewModel 的工厂。

ViewModelStore 来自 ComponentActivity 中的 getViewModelStore() 方法,Factory 来自NewInstanceFactory.getInstance()

我们先来看看如何从 ViewModelStore 中获取 ViewModel,获取 ViewModel 调用了 ViewModelProvider 的get(@NonNull Class<T> modelClass)方法:

public class ViewModelProvider {

    private static final String DEFAULT_KEY =
            "androidx.lifecycle.ViewModelProvider.DefaultKey";

    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
        // 获取 canonicalName ,其中包含包路径和类名
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }


    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        // 通过 key 从 mViewModelStore 中获取 viewModel
        ViewModel viewModel = mViewModelStore.get(key);
        // 判断 viewModel 是否是 modelClass 或其子类的实例
        if (modelClass.isInstance(viewModel)) {
            if (mFactory instanceof OnRequeryFactory) {
                ((OnRequeryFactory) mFactory).onRequery(viewModel);
            }
            // 返回
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
        } else {
            // 没有获取到,使用 mFactory 创建
            viewModel = mFactory.create(modelClass);
        }
        // 存入mViewModelStore
        mViewModelStore.put(key, viewModel);
        // 返回
        return (T) viewModel;
    }

}

从上面的代码可以看到,ViewModel 以 key-value 的形式存储在 mViewModelStore 中,如果 mViewModelStore 中找不到 ViewModel,就使用 mFactory 创建,然后再存入 mViewModelStore。

mFactory 来自 NewInstanceFactory.getInstance(),NewInstanceFactory 代码如下:

public class ViewModelProvider {

    public static class NewInstanceFactory implements Factory {

        private static NewInstanceFactory sInstance;

        @NonNull
        static NewInstanceFactory getInstance() {
            if (sInstance == null) {
                sInstance = new NewInstanceFactory();
            }
            return sInstance;
        }

        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            //noinspection TryWithIdenticalCatches
            try {
                // 直接通过 newInstance() 创建类的实例
                return modelClass.newInstance();
            } catch (InstantiationException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            }
        }
    }
}

如果 mViewModelStore 中找不到 ViewModel ,会直接反射创建 ViewModel 的实例存入 mViewModelStore。

ViewModelStore类的代码如下:

public class ViewModelStore {

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        // 返回旧的 ViewModel
        ViewModel oldViewModel = mMap.put(key, viewModel);
        // 旧的 ViewModel 不为空,调用其 onCleared() 方法
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

    final ViewModel get(String key) {
        return mMap.get(key);
    }

    Set<String> keys() {
        return new HashSet<>(mMap.keySet());
    }


    public final void clear() {
        // 遍历 ViewModel 并调用其 clear() 方法
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        // mMap 清空
        mMap.clear();
    }
}

ViewModelStore 中使用 HashMap 存储 ViewModel,由此可知,只要 ViewModelStore 不变,其中存储的 ViewModel 就不会变。

前面我们看到 getViewModelStore() 方法来自 ComponentActivity:

public class ComponentActivity implements ViewModelStoreOwner {

    private ViewModelStore mViewModelStore;

    public ViewModelStore getViewModelStore() {
        // 判断 getApplication() 是否为 null
        // 给 mApplication 赋值在 Activity 的 attach() 方法中,由此可知
        // 获取 ViewModelStore 需要在 attach() 方法之后
        if (getApplication() == null) {
            throw new IllegalStateException("Your activity is not yet attached to the "
                    + "Application instance. You can't request ViewModel before onCreate call.");
        }
        ensureViewModelStore();
        return mViewModelStore;
    }

    void ensureViewModelStore() {
        if (mViewModelStore == null) {
            // 先会去 getLastNonConfigurationInstance() 中获取 NonConfigurationInstances
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // 从 NonConfigurationInstances 中获取 ViewModelStore 
                mViewModelStore = nc.viewModelStore;
            }
            // 没有获取到,新建
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
    }
}

当我们调用 getViewModelStore() 获取 ViewModelStore 时,先会去 Activity 的getLastNonConfigurationInstance() 中获取 NonConfigurationInstances,拿到里面存储的viewModelStore,如果没有,就 new ViewModelStore()。getLastNonConfigurationInstance() 代码如下:

public class Activity {

    NonConfigurationInstances mLastNonConfigurationInstances;

    final void attach(NonConfigurationInstances lastNonConfigurationInstances) { 
        ...
        mLastNonConfigurationInstances = lastNonConfigurationInstances;
        ...
    }

    @Nullable
    public Object getLastNonConfigurationInstance() {
        return mLastNonConfigurationInstances != null
                ? mLastNonConfigurationInstances.activity : null;
    }
}

由此可知,ComponentActivity 的 NonConfigurationInstances 来自 Activity 的mLastNonConfigurationInstances.activity,mLastNonConfigurationInstances 赋值在 Activity 的 attach() 方法中。

这里先不管,第一次调用 getViewModelStore() 时,mViewModelStore 为 null,新建一个 ViewModelStore 赋值给 mViewModelStore,但是上面并没有看到把 mViewModelStore 存入 ComponentActivity 的 NonConfigurationInstances 的代码。

把 mViewModelStore 存入 ComponentActivity 的 NonConfigurationInstances 在onRetainNonConfigurationInstance() 方法中,这里会将 mViewModelStore 存入NonConfigurationInstances,顾名思义,非配置实例,即不受配置更改影响的实例。这里NonConfigurationInstances 是 ComponentActivity 的静态内部类:

public class ComponentActivity {

    static final class NonConfigurationInstances {
        Object custom;
        ViewModelStore viewModelStore;
    }

    @Override
    @Nullable
    public final Object onRetainNonConfigurationInstance() {
        // Maintain backward compatibility.
        Object custom = onRetainCustomNonConfigurationInstance();

        ViewModelStore viewModelStore = mViewModelStore;
        if (viewModelStore == null) {
            // No one called getViewModelStore(), so see if there was an existing
            // ViewModelStore from our last NonConfigurationInstance
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                viewModelStore = nc.viewModelStore;
            }
        }

        if (viewModelStore == null && custom == null) {
            return null;
        }

        // 将 viewModelStore 存入 ComponentActivity 的 NonConfigurationInstances 并返回
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = viewModelStore;
        return nci;
    }
}

onRetainNonConfigurationInstance() 方法又是在哪里调用的呢?

在这里添加断点,旋转屏幕,可以看到调用堆栈信息,如下:

293ea5d1e23f3198e83809fdc989fd8a.png

Activity 因配置更改而重建时,系统将执行Relaunch流程,系统在这个过程中通过同一个 ActivityClientRecord 来完成信息传递,会销毁当前 Activity ,紧接着再马上重建同一个 Activity 。我们先来看看 handleRelaunchActivity() 方法:

public final class ActivityThread {

    final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();

    @Override
    public void handleRelaunchActivity(ActivityClientRecord tmp,
                                       PendingTransactionActions pendingActions) {
        ...
        // 从 mActivities 中获取 ActivityClientRecord
        ActivityClientRecord r = mActivities.get(tmp.token);
        ...
        handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents,
                pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity");
    }

    private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,
                                             List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents,
                                             PendingTransactionActions pendingActions, boolean startsNotResumed,
                                             Configuration overrideConfig, String reason) {
        ...
        // 这里调用 Activity 的 onPause() 方法
        performPauseActivity(r, false, reason, null /* pendingActions */);
        ...
        // 这里调用 Activity 的 onStop() 方法
        callActivityOnStop(r, true /* saveState */, reason);
        ...
        // 这里调用 Activity 的 onDestroy() 方法
        handleDestroyActivity(r.token, false, configChanges, true, reason);
        ...
        // 这里调用 Activity 的 attach() 方法并传入 ActivityClientRecord
        handleLaunchActivity(r, pendingActions, customIntent);
        ...
    }
}

handleRelaunchActivity() 方法从 mActivities 中获取 ActivityClientRecord 然后传给handleRelaunchActivityInner() 方法,handleRelaunchActivityInner() 方法中顺序调用了performPauseActivity()、callActivityOnStop()、handleDestroyActivity()、handleLaunchActivity(),其中 handleLaunchActivity() 方法中会调用 Activity 的 attach() 方法。

这里 handleDestroyActivity() 方法中又调用了 performDestroyActivity() 方法:

public final class ActivityThread{
    @Override
    public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,
        boolean getNonConfigInstance, String reason) {
        // 调用 performDestroyActivity() 方法 
        ActivityClientRecord r = performDestroyActivity(token, finishing,
        configChanges, getNonConfigInstance, reason);
        ... 
    } 
}

performDestroyActivity() 方法代码如下:

public final class ActivityThread {

    ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
                                                int configChanges, boolean getNonConfigInstance, String reason) {
        ActivityClientRecord r = mActivities.get(token);
        ...
        if (getNonConfigInstance) {
            try {
                // 在这里调用 Activity 的 retainNonConfigurationInstances() 方法,
                // 获取 NonConfigurationInstances 存入 r 中
                r.lastNonConfigurationInstances
                        = r.activity.retainNonConfigurationInstances();
            } catch (Exception e) {
                ...
            }
        }
        ...
        return r;
    }
        
}

在 performDestroyActivity() 中,通过 Activity 的 retainNonConfigurationInstances() 方法获取ActivityNonConfigurationInstances赋值给r.lastNonConfigurationInstances,就相当于修改了mActivities中对应的的ActivityClientRecord

而上面handleLaunchActivity()方法传入ActivityClientRecord跟这里是同一个,也就导致handleLaunchActivity() 方法传入的 ActivityClientRecord 也同步修改了。

Activity 的 retainNonConfigurationInstances() 方法代码如下:

public class Activity {

    // 注意这里的 NonConfigurationInstances 与 ComponentActivity 中的不一样
    static final class NonConfigurationInstances {
        Object activity;
        HashMap<String, Object> children;
        FragmentManagerNonConfig fragments;
        ArrayMap<String, LoaderManager> loaders;
        VoiceInteractor voiceInteractor;
    }

    NonConfigurationInstances retainNonConfigurationInstances() {
        // ComponentActivity 是其子类,调用 ComponentActivity 的
        // onRetainNonConfigurationInstance() 方法
        Object activity = onRetainNonConfigurationInstance();
        ...
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.activity = activity;
        nci.children = children;
        nci.fragments = fragments;
        nci.loaders = loaders;
        if (mVoiceInteractor != null) {
            mVoiceInteractor.retainInstance();
            nci.voiceInteractor = mVoiceInteractor;
        }
        return nci;
    }
}

由于 ComponentActivity 是 Activity 的子类,retainNonConfigurationInstances() 方法调用了ComponentActivity 的 onRetainNonConfigurationInstance() 方法,将 ComponentActivity 中的 NonConfigurationInstances 赋值给 ActivityNonConfigurationInstances 中的 activity,注意这两个 NonConfigurationInstances 是不一样的。

总结一下:
大致流程是这样的,ViewModel 存储在 ViewModelStore 中,Activity 因配置更改销毁时,先将ViewModelStore 存入 ComponentActivity 的 NonConfigurationInstances,然后又把这个NonConfigurationInstances 存入了 Activity 的 NonConfigurationInstances,再存入ActivityClientRecord,最后存入 ActivityThread 的 ArrayMap(mActivities)中。Activity 重建时,调用 Activity 的 attach() 方法,传入的是同一个 ActivityClientRecord,以后每次调用 getViewModelStore()方法取的都是这里存储的 ViewModelStore,这就是 ViewModel 不受配置更改影响的原因。

什么时候会清理 ViewModelStore 中的数据呢?
在 Activity 中,非配置变更触发的销毁会清除 ViewModelStore 中的数据:

public class ComponentActivity {

    public ComponentActivity() {
        ...
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                                       @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    mContextAwareHelper.clearAvailableContext();
                    // 判断非配置变更,清理 ViewModelStore
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });
        ...
    }
}

使用 onSaveInstanceState() 方法保存数据与使用 ViewModel 保存数据的区别:

  1. onSaveInstanceState() 是保存到 Bundle 中,只能保存 Bundle 能接收的数据类型,包括一些基本类型的数据和序列化的类型,而 ViewModel 可以保存任意类型的数据。
  2. onSaveInstanceState() 受到 Binder 事务缓冲区大小限制,只可以存储小容量的数据。 ViewModel 可以存储大容量的数据,但是会受到 App 内存空间的限制。
  3. onSaveInstanceState() 数据最终存储到 ActivityManagerService 的 ActivityRecord 中了,也就是存到系统进程中去了,所以 App 被杀之后还是能恢复。而 ViewModel 数据是存储到 ActivityClientRecord 中,也就是存到应用本身的进程中了,App 被杀后没法恢复。