Android-Jetpack笔记-ViewModelSavedState
时间:2022-07-23
本文章向大家介绍Android-Jetpack笔记-ViewModelSavedState,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
上篇文章提到,虽然viewModel
要比onSaveInstanceState
简单,但是viewModel
只能在屏幕旋转和语言切换后(即配置变更时)的页面重建维持数据,当页面意外销毁时数据无法恢复(viewModel也会重建),而这点onSaveInstanceState
可以做到。关于意外销毁,我们暂且理解成非配置变更引起的销毁重建,比如内存不足等场景。
Jetpack笔记代码
本文源码基于SDK 29
问题复现
引入依赖:
def lifecycle_version = "2.2.0"
//extensions包含Lifecycles、LiveData、ViewModel
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
创建ViewModel
,
class CommonViewModel extends ViewModel {
public MutableLiveData<String> text = new MutableLiveData<>();
}
在布局文件中使用,
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="com.holiday.jetpackstudy.viewmodel_livedata.CommonViewModel" />
<variable
name="commonViewModel"
type="CommonViewModel" />
</data>
<TextView
android:id="@+id/tv_text"
android:text="@{commonViewModel.text}"
android:textSize="@dimen/tv_text_size" />
</layout>
在act中使用,
class ViewModelActivity extends BaseActivity {
CommonViewModel mCommonViewModel;
String mTime;
void onCreate(Bundle savedInstanceState) {
//传this,基于act创建viewModel
mCommonViewModel = ViewModelProviders.of(this).get(CommonViewModel.class);
mBinding.setCommonViewModel(mCommonViewModel);
//观察数据变化
mCommonViewModel.text.observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
//更新UI
mBinding.tvText.setText(s);
}
});
//在页面被意外销毁后,ViewModel会重建
QrLog.e(String.valueOf(mCommonViewModel.hashCode()));
if (null == savedInstanceState) {
mTime = String.valueOf(System.currentTimeMillis() / 1000);
QrLog.e("onCreate 获取当前时间 = " + mTime);
} else {
mTime = savedInstanceState.getString("test");
QrLog.e("onCreate 恢复上次时间 = " + mTime);
}
}
void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//在页面被意外销毁时,存储act的创建时间
outState.putString("test", mTime);
}
}
在onCreate方法中,新加了savedInstanceState
的取值操作,同时重写了onSaveInstanceState
方法存储时间,那么如何模拟页面被意外销毁呢,可以在开发者选项中选中不保留活动-用户离开后即销毁每个活动
,开启后,运行app,然后按home键引起页面意外销毁,然后回到页面,查看日志:
可见当页面意外销毁时,viewModel并不能很好的维持数据。
解决
如果需要让ViewModel
能在页面意外销毁时维持数据,那就需要结合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);
QrLog.e("SavedStateViewModel 初始化数据 = " + time);
} else {
QrLog.e("SavedStateViewModel 恢复数据 = " + text);
}
}
}
然后在act中加入:
//ViewModelActivity.java
class ViewModelActivity extends BaseActivity {
SavedStateViewModel mSavedStateViewModel;
void onCreate(Bundle savedInstanceState) {
//这边创建时传入了SavedStateViewModelFactory
mSavedStateViewModel = ViewModelProviders
.of(this, new SavedStateViewModelFactory(getApplication(), this))
.get(SavedStateViewModel.class);
QrLog.e("mSavedStateViewModel hashCode = " + mSavedStateViewModel.hashCode());
}
}
运行到该页面,点击home键触发意外销毁,然后回到页面,查看日志,
发现虽然mSavedStateViewModel
不再是同一个实例,但是数据是可以恢复的。
至于原理,大致的思路就是在SavedStateViewModelFactory
中,
//SavedStateViewModelFactory.java
<T extends ViewModel> T create(String key, Class<T> modelClass) {
//借助SavedStateHandleController存储了SavedStateHandle
SavedStateHandleController controller = SavedStateHandleController.create(
mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
//创建viewmodel时传入SavedStateHandle
T viewmodel = constructor.newInstance(controller.getHandle());
}
而在SavedStateHandleController
中,
//SavedStateHandleController.java
static SavedStateHandleController create(SavedStateRegistry registry, Lifecycle lifecycle,
String key, Bundle defaultArgs) {
//通过act类名生成的key找到Bundle
Bundle restoredState = registry.consumeRestoredStateForKey(key);
//通过Bundle恢复数据,具体实现看下一个方法
SavedStateHandle handle = SavedStateHandle.createHandle(restoredState, defaultArgs);
//包装成SavedStateHandleController进行返回
SavedStateHandleController controller = new SavedStateHandleController(key, handle);
return controller;
}
//SavedStateHandle.java
static SavedStateHandle createHandle(Bundle restoredState,Bundle defaultState) {
if (restoredState == null && defaultState == null) {
return new SavedStateHandle();
}
//数据恢复
Map<String, Object> state = new HashMap<>();
ArrayList keys = restoredState.getParcelableArrayList(KEYS);
ArrayList values = restoredState.getParcelableArrayList(VALUES);
for (int i = 0; i < keys.size(); i++) {
state.put((String) keys.get(i), values.get(i));
}
//虽然SavedStateHandle不再是同一个实例,但是数据都被恢复过来了
return new SavedStateHandle(state);
}
即本质还是通过Bundle
的序列化和反序列化来恢复数据的。
参考
- B站-jetpack课程ViewModelSavedState
- TableLayout(表格布局)
- 【MindiaX实例】 PHP 在foreach 中获取JSON 单个数据
- 史上十大最严重黑客袭击事件盘点
- LinearLayout(线性布局)
- 服务化了,没想到耦合更加严重?
- 利用好注册的域名
- Android中TextView
- 腾讯 DCI 上线基于集中控制的 SR-TE 方案
- 如何从VS2003升级到VS2008
- js中多个Date对象变量间赋值互相影响
- 并发编程之Executor,Executors,ExecutorService和ThreadPoolExecutor
- 【DeveMobile实例】d3.js 与Trianglify 制作SVG格式Low-Poly 特效
- 未来人工智能将把人类分为3层,而你会在哪一层呢?
- IIS 7.0探索用于 Windows Vista 的 Web 服务器和更多内容
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Apache Curator操作zookeeper的API使用
- 微信公众号开发-自定义菜单接口
- 基于JDK命令行工具的监控
- 基于JVisualVM的可视化监控
- 基于Btrace的监控调试
- 大数据框架—Flink与Beam
- Mybatis动态SQL
- Mybatis-Generator插件的使用与Spring集成Mybatis的配置
- Mybatis的缓存机制详解
- zookeeper基本特性与基于Linux的ZK客户端命令行学习
- Apache Curator操作zookeeper的API使用
- 使用Java API操作zookeeper的acl权限
- 使用ZooKeeper提供的原生Java API操作ZooKeeper节点
- CountDownLatch类的使用
- Spring-如何给静态变量注入值