ViewModel
ViewModel是用来保存和操作UI相关的数据的,这样即使configuration发生改变,数据仍然可以存在。
引入ViewModel的原因有三点:
Activity和Fragment等App组件的生命周期都是由系统控制的,是开发者不可控的,保存在其中的数据就有丢失的危险。虽然可以通过onSaveInstanceState()来保存数据,可是这个回调只适合用来保存少量数据比如UI状态,对于一些大量数据比如列表数据就不合适了。
而且Activity和Fragment中都可能进行一些异步操作,这就需要在销毁的时候去清空回调避免内存泄露。或者界面重建后还要重新获取数据,也会浪费资源。
UI控制器本身就负责处理用户交互和系统交互,如果还需要处理数据问题,就会导致职责过多。
所以有必要从UI控制器中抽离出数据的控制权。Lifecycle库提供了ViewModel类用来给UI提供数据。ViewModel不受configuration改变的影响。
ViewModel的示例:
public class MyViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<List<Users>>();
loadUsers();
}
return users;
}
private void loadUsers() {
// do async operation to fetch users
}
}
Activity中的使用:
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// update UI
});
}
}
如果Activity重建了,仍然可以接收到之前Activity所创建的ViewModel。如果该Activity销毁了,ViewModel的onCleared()会被调用,清空资源。
注意:因为ViewModel独立于Activity和Fragment,所以不能引用任何View,或者任何引用了Context 的对象。如果ViewModel需要一个Application类型的Context,可以继承于AndroidViewModel类,构造方法中会有一个Application对象。
在Fragment间分享数据
Fragment间经常需要分享数据,通常是定义接口,然后通过Activity联系在一起。但是Fragment间的生命周期又可能存在不同步,问题就变得比较复杂了。
假设现在有个列表Fragment,还有一个内容Fragment,点击列表Fragment某一项会更新内容Fragment,使用ViewModel可以比较方便地处理数据问题。可以通过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 LifecycleFragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// update UI
});
}
}
这样做的好处是:
- Activity不用再负责两个Fragment之间的联系
- Fragment只需要知道ViewModel,不需要知道其他的Fragment,耦合性降低
- 每个Fragment的生命周期相互独立互不影响。
ViewModel的生命周期
ViewModel和SavedInstanceState
ViewModel在Activity的configuration改变过程中可以保持数据不变,但是如果系统把应用杀死掉就没办法了。
如果用户长时间离开应用再进来,应用进程可能已经被系统杀掉了,此时系统会负责恢复之前保存的SavedInstanceState。在onSaveInstanceState()中保存的数据是放在系统进程内存中的,Android系统只允许存放少量的数据,所以最好不要存放一些自定义类的对象进去,可以把自定义对象保存到数据库中,onSaveInstanceState中只保留对象的某个字段比如id,然后再使用ViewModel根据这个id去获取完整的数据。
上一篇: PHP之内置web服务器
推荐阅读
-
Android通过ViewModel保存数据实现多页面的数据共享功能
-
Android-ViewModel和LiveData使用详解
-
使用MVVM的常见误区(1)在ViewModel中和用户交互
-
【Medium 万赞好文】ViewModel 和 LIveData:模式 + 反模式
-
WPF 如何在ViewModel中获取ListView 的 SelectedItems
-
WPF学习笔记 MVVM模式下,ViewModel如何关闭View
-
WPF MVVM 如何在 ViewModel 中关闭界面窗口
-
【Android】ViewModel 用法及源码解析
-
领域模型(DomainModel)与视图模型(ViewModel)
-
Android开发之MVVM模式实践(一):ViewModel的封装