The ViewModel class is designed to store and manage UI-related data so that the data survives configuration changes such as screen rotations.
ViewModel类的设计是为了存储和管理Ui相关的数据,例如配置文件如屏幕旋转使数据保留下来
应用程序组件(如activity或者fragment),是由android的Framework框架管理的生命周期。框架决定销毁或者创建她们,这是基于一些用户的行为或者设备的事件,而这一切都在你的控制范围外。
因为一些对象可能会被系统重建或者销毁,你所保存的任何数据都会丢失。例如:如果你的activity中有一些用户列表,当配置文件更改导致的activity重建,新的activity就必须重新获取用户列表,对于简单的数据,activity可以从onSaveInstanceState()方法或者onCreate()的Bundle中重新获取数据,但是这个方法仅仅适用于小的数据例如UI状态,不能是大量的数据,例如用户列表。
另一个问题是,这些Ui控制器(activity或者fragment)经常进行需要一些时间的一步操作。Ui控制器需要管理这些回调,并在销毁的时候清理它们,避免内存泄漏。这需要大量的维护,并且在进行更改配置而从新创建对象的情况下,这是浪费资源,因为需要发出相同的调用。
将视图数据所有权与UI控制器逻辑分离是更容易和更有效,Lifecycles提供了一个名为ViewModel的新类。用于UI控制器的辅助类,负责为UI准备数据。在配置更改期间,ViewModel将自动保留,以便其保存的数据立即可用于下一个activity或fragment实例。ViewModel应该是获取和保留用户列表而不是fragment或activity的责任。
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
}
}
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
});
}
}
由于ViewModel超出了特定的fragment和activity实例,所以它不应该引用View或任何可能持有对活动上下文的引用的类。如果ViewModel需要Application上下文(例如,找到系统服务),则可以扩展AndroidViewModel类,并在构造函数中接收Application的构造函数(由于Application类扩展了Context)
可以理解为ViewMode不要持有Context,如果必须使用context就实现AndroidViewModel.
在Fragment之间共享数据
使用ViewModel对象解决activity中多个fragment相互通信。其中我们有一个片段,用户从列表中选择一个项目,另一个片段显示所选项目的内容。
这些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 onActivityCreated() {
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends LifecycleFragment {
public void onActivityCreated() {
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// update UI
});
}
}
请注意,在获取ViewModelProvider时,两个fragment都使用getActivity()。这意味着他们都将收到相同的SharedViewModel实例,该实例是作用域的活动。
这种方法的好处包括:
- activity不需要做任何事情,也不需要知道通信的任何内容。
- 除了SharedViewModel之外,fragment不需要彼此了解。如果其中一个消失,另一个会照常工作
- 每个片段都有自己的生命周期,不受其他片段的生命周期的影响。实际上,在一个片段替换另一个片段的UI中,UI工作没有任何问题