Android架构组件:ViewMode概述
作用:
ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。
问题:
(1) Android 框架可以管理界面控制器(如 Activity, Fragment)的生命周期。由Android 框架响应的某些用户操作或设备事件,用户无法控制。
当系统销毁或重新创建界面控制器,则存储在其中的任何临时性界面相关数据都会丢失。对于简单的数据,Activity可以使用onSaveInstanceState()存储数据,组件重建后从onCreate()中的Bundle恢复其数据,但此方法仅适合可以序列化再反序列化的少量数据,如果数据量较大,如用户列表或位图,则不适合。
(2)界面控制器经常需要进行异步调用,这些调用可能需要一些时间才能返回结果,有可能会出现UI组件已销毁,而请求还未返回的情况。在因配置更改而重新创建对象的情况下,对象可能需要重新发送请求,会造成资源的浪费
(3)应该遵循职责分离原则,将视图数据从界面控制器逻辑中分离出来,这样不会导致界面控制器类代码膨胀
ViewModel的用法:
架构组件为界面控制器提供了 ViewModel 辅助程序类,该类负责为界面准备数据。
在配置更改期间会自动保留 ViewModel 对象,以便它们存储的数据立即可供下一个Activity/Fragment实例使用。如以下示例代码所示:
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 访问该列表
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
});
}
}
如果Activity被重新创建了,它会收到被之前Activity创建的相同MyViewModel实例。当所属Activity终止后,框架调用ViewModel的onCleared()方法清除资源。
因为ViewModel在指定的Activity或Fragment实例外存活,它应该永远不能引用一个View,或持有任何包含Activity context引用的类。如果ViewModel需要Application的context(如获取系统服务),可以扩展AndroidViewmodel,并拥有一个构造器接收Application。
ViewModel 的生命周期
ViewModel 对象存在的时间范围是获取ViewModel时传递给ViewModelProvider的Lifecycle。ViewModel将一直留在内存中,直到限定其存在时间范围的Lifecycle 永久消失:对于 Activity,是在Activity完成时;而对于Fragment,是在Fragment分离时。
上图左侧为Activity的生命周期过程,期间有一个旋转屏幕的操作;右侧则为ViewModel的生命周期过程。
一般通过如下代码初始化ViewModel:
viewModel = ViewModelProviders.of(this).get(UserProfileViewModel.class);
// this参数一般为Activity或Fragment,因此ViewModelProvider可以获取组件的生命周期。
Activity在生命周期中可能会触发多次onCreate(),而ViewModel则只会在第一次onCreate()时创建,然后直到最后Activity销毁。
在Fragment间共享数据
一个Activity中的多个Fragment相互通讯是很常见的。假设有一个Fragment,在该Fragment 中,用户从列表中选择一项,还有另一个Fragment,用于显示选定项的内容。这种情况不太容易处理,因为这两个 Fragment都需要定义某种接口描述,并且所有者Activity必须将两者绑定在一起。此外,这两个 Fragment 都必须处理另一个Fragment尚未创建或不可见的情况。
可以使用 ViewModel 对象解决这一常见的难点。这两个Fragment可以使用其 Activity 范围共享 ViewModel 来处理此类通信,如以下示例代码所示:
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.
});
}
}
注意:这两个Fragment都会检索包含它们的Activity。这样,当这两个Fragment各自获取ViewModelProvider时,它们会收到相同的SharedViewModel实例(其范围限定为该Activity)。
此方法具有以下优势:
* Activity 不需要执行任何操作,也不需要对此通信有任何了解。
* 除了SharedViewModel约定之外,Fragment不需要相互了解。如果其中一个Fragment 消失,另一个Fragment将继续照常工作。
* 每个Fragment 都有自己的生命周期,而不受另一个Fragment的生命周期的影响。如果一个Fragment替换另一个Fragment,界面将继续工作而没有任何问题。
参考:
https://developer.android.google.cn/topic/libraries/architecture/viewmodel.html#java
https://blog.csdn.net/qq_24442769/article/details/79426609
https://blog.csdn.net/zhuzp_blog/article/details/78910535