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
网友评论