在使用一个新的组件之前,我们需要了解为什么需要使用它、如何使用、使用过程中的注意事项、可扩展或可提升的地方。当我们深入透彻理解这些后,开发中遇到任何问题都可以迎刃而解。当然需要了解这些内容,我们必须熟悉源码的实现过程,这样才能做到心中有数。
ViewModel主要是为了保存和管理UI相关的数据,能够在我们的配置发生变化的时候保存数据,比如在屏幕旋转时,可以直接使用上次保存的ViewModel对象以及其中的数据。
我们知道,当屏幕旋转,默认情况一下原有的Activity会销毁,从而重新创建新的Activity,此时,UI控制器存储的相关数据会丢失,重新执行onCreate()等生命周期方法,从而重新加载我们需要的数据。从UI体验来讲,又需要再次等待一个加载数据(网络或者本地数据库)的过程;从技术的角度来讲,消耗不必要的系统资源做以前已经完成过的事。如果我们想保存数据,有一种简单的方法,就是使用使用onSaveInstanceState(),但是它只能存储少量的可序列化的数据,不适合大量的数据或者类似bitmap之类的。如果使用ViewModel则就能解决上面的问题。
public class MeViewModel extends ViewModel {
private MutableLiveData userInfo;
//一般我们在UI的onCreate()中异步加载数据,因此需要按照以下方式操作,才能保证再次onCrate()不会重复异步加载数据。
public LiveData getUser(){
if(userInfo == null){
userInfo = new MutableLiveData<>();
loadUser();
}
return userInfo;
}
private void loadUser(){
//from net or db
//userInfo.postValue(userEntity);
}
//可在Activity或者Fragment onDestroy()之前做一些操作
@Override
protected void onCleared() {
super.onCleared();
}
}
public class TestViewModel extends AndroidViewModel {
public TestViewModel(@NonNull Application application) {
super(application);
}
public void loadData(){
//可以使用全局的Application
Application application = getApplication();
//do other
}
}
public class MeActivity extends AppCompatActivity {
private MeViewModel viewModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = ViewModelProviders.of(this).get(MeViewModel.class);
viewModel.getUser().observe(this, new Observer() {
@Override
public void onChanged(@Nullable UserEntity userEntity) {
//update UI
}
});
}
}
ViewModel中不能持有Activity、Fragment、View的引用,因为ViewModel的生命周期比当前绑定的Activity或者Fragment更长,会导致内存泄漏。
ViewModel对象的恢复是在这个地方执行的,但是最终的实现原理还没有研究
protected void onCreate(@Nullable Bundle savedInstanceState) {
this.mFragments.attachHost((Fragment)null);
super.onCreate(savedInstanceState);
FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
if (nc != null && nc.viewModelStore != null && this.mViewModelStore == null) {
this.mViewModelStore = nc.viewModelStore;
}
......
}
存储大量的数据和onSaveInstance()存储少量可序列化原理还未研究
我们在Activity中使用ViewModel是按照下面的方式使用的,那么保存的数据是如何刷新的UI的?
public class MeActivity extends AppCompatActivity {
private MeViewModel viewModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = ViewModelProviders.of(this).get(MeViewModel.class);
viewModel.getUser().observe(this, new Observer() {
@Override
public void onChanged(@Nullable UserEntity userEntity) {
//update UI
}
});
}
}
这里其中的妙处在LiveData,onCreate()重新执行,执行observe方法,添加新的LifecycleBoundObserver,而默认LifecycleBoundObserver的mLastVersion为START_VERSION,而此时原有的LiveData的mVersion版本号大于START_VERSION版本号,因此会回调onChanged()方法。
public abstract class LiveData {
.....
static final int START_VERSION = -1;
private int mVersion = START_VERSION;
//改变mVersion值
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
//添加LifecycleBoundObserver
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver{
.......
}
private abstract class ObserverWrapper {
final Observer mObserver;
boolean mActive;
//默认值
int mLastVersion = START_VERSION;
.....
}
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
//回调onChanged()方法
observer.mLastVersion = mVersion;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
.....
}