1.介绍
ViewModel,意为 视图模型,即 为界面准备数据的模型。就是ViewModel为UI层提供数据。
官方文档定义如下:
- ViewModel 以注重生命周期的方式存储和管理界面相关的数据。(作用)
- ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。(特点)
作用: - 因配置更改导致页面重建后可以保存页面数据
- ViewModel不持有View 在数据变更的时候通知View数据变更
- ViewModel的生命周期与Activity的生命周期绑定,可以有效的防止内存泄露
2.ViewModel使用 - 继承ViewModel自定义MyViewModel
- 在MyViewModel中编写获取UI数据的逻辑
- 使用LiveData将获取到的UI数据抛出
- 在Activity/Fragment中使用ViewModelProvider获取MyViewModel实例
- 观察MyViewModel中的LiveData数据,进行对应的UI更新。
public class UserViewModel extends ViewModel {
private MutableLiveData<String> userLiveData ;
private MutableLiveData<Boolean> loadingLiveData;
public UserViewModel() {
userLiveData = new MutableLiveData<>();
loadingLiveData = new MutableLiveData<>();
}
//获取用户信息,假装网络请求 2s后 返回用户信息
public void getUserInfo() {
loadingLiveData.setValue(true);
new AsyncTask<Void, Void, String>() {
@Override
protected void onPostExecute(String s) {
loadingLiveData.setValue(false);
userLiveData.setValue(s);//抛出用户信息
}
@Override
protected String doInBackground(Void... voids) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String userName = "......";
return userName;
}
}.execute();
}
public LiveData<String> getUserLiveData() {
return userLiveData;
}
public LiveData<Boolean> getLoadingLiveData() {
return loadingLiveData;
}
}
UserViewModel继承ViewModel,然后逻辑很简单:假装网络请求 2s后 返回用户信息,其中userLiveData用于抛出用户信息,loadingLiveData用于控制进度条显示。
在看UI层
public class UserActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
Log.i(TAG, "onCreate: ");
TextView tvUserName = findViewById(R.id.textView);
ProgressBar pbLoading = findViewById(R.id.pb_loading);
//获取ViewModel实例
ViewModelProvider viewModelProvider = new ViewModelProvider(this);
UserViewModel userViewModel = viewModelProvider.get(UserViewModel.class);
//观察 用户信息
userViewModel.getUserLiveData().observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
// update ui.
tvUserName.setText(s);
}
});
userViewModel.getLoadingLiveData().observe(this, new Observer<Boolean>() {
@Override
public void onChanged(Boolean aBoolean) {
pbLoading.setVisibility(aBoolean?View.VISIBLE:View.GONE);
}
});
//点击按钮获取用户信息
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
userViewModel.getUserInfo();
}
});
}
@Override
protected void onStop() {
super.onStop();
Log.i(TAG, "onStop: ");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy: ");
}
}
页面有个按钮用于点击获取用户信息,有个TextView展示用户信息。 在onCreate()中先 创建ViewModelProvider实例,传入的参数是ViewModelStoreOwner,Activity和Fragment都是其实现。然后通过ViewModelProvider的get方法 获取ViewModel实例,然后就是 观察ViewModel中的LiveData。
源码分析
我们主要分析一个部分 ViewModel是如何存储数据的,以为什么页面的重建不会导致数据丢失。
public abstract class ViewModel {
...
private volatile boolean mCleared = false;
//在ViewModel将被清除时调用
//当ViewModel观察了一些数据,可以在这里做解注册 防止内存泄漏
@SuppressWarnings("WeakerAccess")
protected void onCleared() {
}
@MainThread
final void clear() {
mCleared = true;
...
onCleared();
}
...
}
ViewModel类 是抽象类,内部没有啥逻辑,有个clear()方法会在ViewModel将被清除时调用。
然后ViewModel实例的获取是通过ViewModelProvider类,见名知意,即ViewModel提供者,来看下它的构造方法: