MVVM+LiveData的一个疑点
之前一直用的MVP开发,最近有新项目要开发,所以想要这套方案来开发,在网上也有很多相关文章。总结了一下,对MVVM+ LiveData的使用一般有两种写法。
- 在Activity或者fragment中
viewModel.getXXXLiveData().observe(this, new Observer<XXX>() {
@Override
public void onChanged(@Nullable XXX xx) {
if (xx!= null) {
//…
//UI更新,或者调用databinding更新ui
}
}
});
在ViewModel获得数据后,直接调用XXXLiveData.setValue(XXX)
很显然第二种要代码要简洁很多,熟悉LiveData的都知道,当调用LiveData的setValue的时候,注册的observer会调用onChanged方法。第二种并没有注册observer,这中间有什么玄机呢。后面以google的android-architecture项目,分支是todo-mvvm-live为例剖析原因。
- 布局文件:部分代码
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View"/>
<variable
name="viewmodel"
type="com.example.android.architecture.blueprints.todoapp.addedittask.AddEditTaskViewModel"/>
</data>
........
- fragment中,databinding设置viewmodel类对象,部分代码
..........
final View root = inflater.inflate(R.layout.addtask_frag, container, false);
if (mViewDataBinding == null) {
mViewDataBinding = AddtaskFragBinding.bind(root);
}
mViewModel = AddEditTaskActivity.obtainViewModel(getActivity());
mViewDataBinding.setViewmodel(mViewModel);
mViewDataBinding.setLifecycleOwner(getActivity());
...........
- viewModel中获得数据,更新UI
public class AddEditTaskViewModel extends ViewModel implements TasksDataSource.GetTaskCallback {
// Two-way databinding, exposing MutableLiveData
public final MutableLiveData<String> title = new MutableLiveData<>();
......
public AddEditTaskViewModel(TasksRepository tasksRepository) {
mTasksRepository = tasksRepository;
}
public void start(String taskId) {
......
mTasksRepository.getTask(taskId, this);
}
@Override
public void onTaskLoaded(Task task) {
title.setValue(task.getTitle());
......
}
这是一个标准的使用mvvm+liveData的demo。
分析
- 从AddtaskFragBinding开始。找到生成的这个类,查看源代码。
AddtaskFragBinding是一个抽象类,实现类是AddtaskFragBindingImpl
public abstract class AddtaskFragBinding extends ViewDataBinding {
@NonNull
public final EditText addTaskDescription;
@NonNull
public final EditText addTaskTitle;
@NonNull
public final ScrollChildSwipeRefreshLayout refreshLayout;
@Bindable
protected AddEditTaskViewModel mViewmodel;
protected AddtaskFragBinding(DataBindingComponent _bindingComponent, View _root,
int _localFieldCount, EditText addTaskDescription, EditText addTaskTitle,
ScrollChildSwipeRefreshLayout refreshLayout) {
super(_bindingComponent, _root, _localFieldCount);
this.addTaskDescription = addTaskDescription;
this.addTaskTitle = addTaskTitle;
this.refreshLayout = refreshLayout;
}
public abstract void setViewmodel(@Nullable AddEditTaskViewModel viewmodel);
@Nullable
public AddEditTaskViewModel getViewmodel() {
return mViewmodel;
}
......
可见setViewmodel是在AddtaskFragBindingImpl中实现。
public class AddtaskFragBindingImpl extends AddtaskFragBinding {
...
public void setViewmodel(@Nullable com.example.android.architecture.blueprints.todoapp.addedittask.AddEditTaskViewModel Viewmodel) {
this.mViewmodel = Viewmodel;
synchronized(this) {
mDirtyFlags |= 0x8L;
}
notifyPropertyChanged(BR.viewmodel);
super.requestRebind();
}
....
}
这里吐槽一个点,在setViewmodel方法中参数Viewmodel的命名没有遵循驼峰命名法,哈哈,也是个小瑕疵。
设置了viewmodel。绑定什么时候开始呢。记得在给databinding设置viewmodel的时候。mViewDataBinding.setLifecycleOwner(getActivity());我们跟下这个流程。这个方法在ViewDataBinding类中
@MainThread
public void setLifecycleOwner(@Nullable LifecycleOwner lifecycleOwner) {
if (mLifecycleOwner == lifecycleOwner) {
return;
}
if (mLifecycleOwner != null) {
mLifecycleOwner.getLifecycle().removeObserver(mOnStartListener);
}
mLifecycleOwner = lifecycleOwner;
if (lifecycleOwner != null) {
if (mOnStartListener == null) {
mOnStartListener = new OnStartListener();
}
lifecycleOwner.getLifecycle().addObserver(mOnStartListener);
}
for (WeakListener<?> weakListener : mLocalFieldObservers) {
if (weakListener != null) {
weakListener.setLifecycleOwner(lifecycleOwner);
}
}
}
核心就是一句代码 lifecycleOwner.getLifecycle().addObserver(mOnStartListener);往lifecycle中添加一个观察者mOnStartListener,lifecycle的原理就不在细诉了,网上有很多讲解这个原理的资料。
public class OnStartListener implements LifecycleObserver {
private OnStartListener() {
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
executePendingBindings();
}
}
得知在start阶段调用executePendingBindings()->executeBindingsInternal->executeBindings。executeBindings的实现在AddtaskFragBindingImpl中
@Override
protected void executeBindings() {
......
com.example.android.architecture.blueprints.todoapp.addedittask.AddEditTaskViewModel viewmodel = mViewmodel;
androidx.lifecycle.MutableLiveData<java.lang.String> viewmodelTitle = null;
......
if (viewmodel != null) {
// read viewmodel.title
viewmodelTitle = viewmodel.title;
}
updateLiveDataRegistration(1, viewmodelTitle);
if (viewmodelTitle != null) {
// read viewmodel.title.getValue()
viewmodelTitleGetValue = viewmodelTitle.getValue();
}
}
......
}
这里以title为例,viewmodelTitle存了livedata类型的变量title,调用updateLiveDataRegistration->updateRegistration
protected boolean updateLiveDataRegistration(int localFieldId, LiveData<?> observable) {
mInLiveDataRegisterObserver = true;
try {
return updateRegistration(localFieldId, observable, CREATE_LIVE_DATA_LISTENER);
} finally {
mInLiveDataRegisterObserver = false;
}
}
private boolean updateRegistration(int localFieldId, Object observable,
CreateWeakListener listenerCreator) {
if (observable == null) {
return unregisterFrom(localFieldId);
}
WeakListener listener = mLocalFieldObservers[localFieldId];
if (listener == null) {
registerTo(localFieldId, observable, listenerCreator);
return true;
}
if (listener.getTarget() == observable) {
return false;//nothing to do, same object
}
unregisterFrom(localFieldId);
registerTo(localFieldId, observable, listenerCreator);
return true;
}
参数observable就是title,但类型怎么变成了Object,为什么这么设计,这里暂且不提,文末在论述。因为首次进来listener 是null,那么调用registerTo()方法
protected void registerTo(int localFieldId, Object observable,
CreateWeakListener listenerCreator) {
if (observable == null) {
return;
}
WeakListener listener = mLocalFieldObservers[localFieldId];
if (listener == null) {
listener = listenerCreator.create(this, localFieldId);
mLocalFieldObservers[localFieldId] = listener;
if (mLifecycleOwner != null) {
listener.setLifecycleOwner(mLifecycleOwner);
}
}
listener.setTarget(observable);
}
listenerCreator.create创建出来的具体对象是什么类型呢。从方法调用来看listenerCreator对象就是CREATE_LIVE_DATA_LISTENER,这个可以在updateLiveDataRegistration看到。
private static final CreateWeakListener CREATE_LIVE_DATA_LISTENER = new CreateWeakListener() {
@Override
public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
return new LiveDataListener(viewDataBinding, localFieldId).getListener();
}
};
那说明了listenerCreator.create()创建的就是LiveDataListener.getListener()返回的对象,还有一句关键代码 listener.setLifecycleOwner(mLifecycleOwner);listener其实是LiveDataListener构造函数中创建。
private static class LiveDataListener implements Observer,
ObservableReference<LiveData<?>> {
final WeakListener<LiveData<?>> mListener;
LifecycleOwner mLifecycleOwner;
public LiveDataListener(ViewDataBinding binder, int localFieldId) {
mListener = new WeakListener(binder, localFieldId, this);
}
@Override
public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
LifecycleOwner owner = (LifecycleOwner) lifecycleOwner;
LiveData<?> liveData = mListener.getTarget();
if (liveData != null) {
if (mLifecycleOwner != null) {
liveData.removeObserver(this);
}
if (lifecycleOwner != null) {
liveData.observe(owner, this);
}
}
mLifecycleOwner = owner;
}
@Override
public WeakListener<LiveData<?>> getListener() {
return mListener;
}
@Override
public void addListener(LiveData<?> target) {
if (mLifecycleOwner != null) {
target.observe(mLifecycleOwner, this);
}
}
@Override
public void removeListener(LiveData<?> target) {
target.removeObserver(this);
}
@Override
public void onChanged(@Nullable Object o) {
ViewDataBinding binder = mListener.getBinder();
binder.handleFieldChange(mListener.mLocalFieldId, mListener.getTarget(), 0);
}
}
private static class WeakListener<T> extends WeakReference<ViewDataBinding> {
private final ObservableReference<T> mObservable;
protected final int mLocalFieldId;
private T mTarget;
public WeakListener(ViewDataBinding binder, int localFieldId,
ObservableReference<T> observable) {
super(binder, sReferenceQueue);
mLocalFieldId = localFieldId;
mObservable = observable;
}
public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
mObservable.setLifecycleOwner(lifecycleOwner);
}
public void setTarget(T object) {
unregister();
mTarget = object;
if (mTarget != null) {
mObservable.addListener(mTarget);
}
}
.....
可以看到WeakListener类中的mObservable其实就是LiveDataListener类,所以最终调用的也是LiveDataListener的setLifecycleOwner,在这个方法里可以看到 liveData.observe(owner, this);这个liveData是mListener.getTarget()返回的,此时应该是null。在registerTo方法的最后一行 listener.setTarget(observable);observable是前面传进来的title,在WeakListener的setTarget中
public void setTarget(T object) {
unregister();
mTarget = object;
if (mTarget != null) {
mObservable.addListener(mTarget);
}
}
调用了 mObservable.addListener(mTarget);回到LiveDataListener的addListener
@Override
public void addListener(LiveData<?> target) {
if (mLifecycleOwner != null) {
target.observe(mLifecycleOwner, this);
}
}
target.observe(mLifecycleOwner, this);似曾相识,target就是liveData类型的title对象,这里就是方法一的写法。
总结
方法二在底层其实也是调用了LiveData.observer方法,经过这么多步骤,终于解释清楚了我们为啥不需要显示observer,原来底层都帮我们处理好了,简化了代码。之前遗留一个问题。updateRegistration方法中第二个参数类型是Object,而不是LiveData,因为observable还有可能是ObservableField或者ObservableXXX,WeakListener是将target泛型化的。所以需要Object。