ViewModel——Google组件开发
ViewModel类旨在存储和管理与UI相关的数据,以便数据在诸如屏幕旋转之类的配置更改中生存下来。它还处理Activity/Fragment与应用程序的其余部分的通信(例如调用业务逻辑类)。
之所以要持久化是基于两个原因:如果OS销毁app释放资源,用户数据不会丢失;当网络很差或者断网的时候app可以继续工作。Model是负责app数据处理的组件。它们不依赖于View或者app 组件(Activity,Fragment等),因此它们不会受那些组件的生命周期的影响。保持UI代码的简单,业务逻辑分离可以让它更易管理。
ViewModel的目的是获取并保存Activity或Fragment所必需的信息。Activity或Fragment应该能够观察到ViewModel中的变化
将视图数据所有权与UI控制器逻辑分离是更容易和更有效的。生命周期提供了一个名为ViewModel的新类,一个用于UI控制器的帮助器类,它负责准备UI的数据。在配置更改期间,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<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
});
}
}
如果Activity重新创建,它将收到由上一个Activity创建的相同的MyViewModel实例。当所有者Activity销毁时,框架调用ViewModel的onCleared()方法,以便它可以清理资源。
由于ViewModel超出了具体的Activity和Fragment实例,所以它不应该引用View或任何可能持有对活动上下文的引用的类。如果ViewModel需要应用程序上下文(例如,找到系统服务),则可以继承AndroidViewModel类,并在构造函数中接收应用程序的构造函数,子类必须具有接受Application作为唯一参数的构造函数。(因为Application类继承了Context)。
在Fragments之间共享数据
Activity中的两个或多个Fragment需要相互通信。因此这两个Fragment需要定义一些接口描述,并且Activity必须将两者绑定在一起。此外,两个Fragment都必须处理其他Fragment尚未创建或不可见的情况。
通过使用ViewModel对象可以解决这个问题。想象一下主从Fragment的常见情况,其中我们有一个Fragment,用户从列表中选择一个项目,另一个Fragment显示所选项目的内容。
这些Fragment可以使用其Activity范围共享一个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 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的作用域。
这种做法的好处:
- 该Activity不需要做任何事情,也不知道有关此通信的任何内容。
- 除了SharedViewModel之外,Fragment不需要彼此了解。如果其中一个消失,另一个会照常工作。
- 每个Fragment都有自己的生命周期,不受其他Fragment的生命周期的影响。
ViewModel的生命周期
ViewModel对象在获取ViewModel时被限定为传递给ViewModelProvider的生命周期。ViewModel保留在内存中,直到Activity销毁或Fragment分离之前。