AAC---ViewModel
ViewModel介绍
ViewModel是用来保存并且管理与LifeCycle以及UI相关数据的数据结构。ViewModel允许数据在Configuration改变时(比如屏幕旋转)保存,并且在旋转后恢复。
UI Controller相关的Android框架则是Activity与Fragment。而FrameWork可能由于用户的操作,设备系统事件决定销毁或者重建UI Controller,而这些操作则完全不可控。而当UI Controller被重建或者销毁时候,任何transient UI相关的数据都会丢失。
例如你的APP可能包括了很多用户的数据,当Activity因为Configuration改变而重建时,新的Activity需要重新获取这些数据,而一般会使用
onSaveInstanceState
方法保存,并且使用onCreate
中的Bundle进行恢复,但是这种只适合非常小并且实现了序列化以及反序列化的数据,而不能保存大数据,比如Bitmap等。
最后,ViewModel非常有效的帮我们从UI Controller隔离了View与数据之间的逻辑关系。
使用ViewModel
- 在build.gradle中添加配置
dependencies {
def lifecycle_version = "1.1.1"
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
// alternatively - just ViewModel
implementation "android.arch.lifecycle:viewmodel:$lifecycle_version" // use -ktx for Kotlin
// alternatively - just LiveData
implementation "android.arch.lifecycle:livedata:$lifecycle_version"
// alternatively - Lifecycles only (no ViewModel or LiveData).
// Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"
// alternately - if using Java8, use the following instead of compiler
implementation "android.arch.lifecycle:common-java8:$lifecycle_version"
}
- 实现ViewModel与LiveData绑定。
- 在ViewModel中提供数据来源repository,如Room或者网络
- 在数据返回后,使用LiveData向UI Controller提供UI相关数据
public class MyViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<List<User>>();
loadUsers();
}
return users;
}
private void loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
- 在Activity或者Fragment中生成对应的ViewModel
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// update UI
});
}
}
ViewModel的生命周期
这样即使Activity被重建了,通过ViewModelProviders
得到的ViewModel
对象还是第一个Activity创建的对象。而当Activity被销毁时,Framework会回调ViewModel
对象的onCleared
方法,以至于可以让我们在该方法内部进行资源清理,避免内存泄漏。
生命周期
ViewModel绝对不能引用View,LifeCycle或者任何一个引用了Activity的对象,否则可能会导致内存泄漏。如果ViewModel需要引用到Application的话,那么则需要使用
AndroidViewModel
对象。
在Fragment之间共享数据
通过同一个Activity获取到的ViewModel对象相同,所以可以通过ViewModelProvider
获取到的ViewModel对象是同一个。而这么做的好处有:
- Activity不需要做任何事情,或者不需要知道Fragment之间有什么交流
- Fragment也不需要知道ViewModel相互之间的关系,一旦另外一个Fragment消失,另外一个也会运行正常。
- 每个Fragment都有自己的生命周期,这样ViewModel不会被任何一个Fragment的周期干扰。一旦一个Fragment替换了另一个,那么UI也不会出问题
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, item -> {
// Update the UI.
});
}
}
参考资料
ViewModel Lifecycle Aware Data Loading with Architecture Components Jetpack
- JSON Web Token - 在Web应用间安全地传递信息
- TensorFlow强化学习入门(2)——基于策略的Agents
- 用ABAP 生成二维码 QR Code
- CDS view注解解析 - @Environment.systemField
- Document flow API in SAP CRM and C4C
- Python基础知识4:文件操作
- Python基础知识6:格式化字符、颜色
- 给自定义控件(Web Control)添加事件的几种方法。前两种方法可以不实现IPostBackEventHandler
- 【开源】QuickPager ASP.NET2.0分页控件 v2.0.0.2版本。
- 【开源】我的分页控件正式命名为QuickPager ASP.NET2.0分页控件
- 【开源】QuickPager ASP.NET2.0分页控件V2.0.0.1——分页控件的源码 (二)
- 高级时钟约束
- 【开源】QuickPager ASP.NET2.0分页控件V2.0.0.1——分页控件的源码(一) 主体
- 【开源】QuickPager ASP.NET2.0分页控件V2.0.0.1——支持多种数据库。让分页更加简单。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法