关于 DataBinding 如何使用 官方文档 已经有详细介绍,该篇文章主要讲解的 DataBinding 的原理,所以基本使用不会赘述。
个人使用 DataBinding 认为还是有使用的注意事项,DataBinding 框架虽然非常强大能处理很多数据绑定操作,但不建议将过多的操作都放在 xml 做数据绑定,应保持尽量以刷新 UI 更新的角度使用 DataBinding,否则当出现问题时,可能会存在难以定位的问题。
在使用 DataBinding 时,为了能做到控件与数据的绑定,xml 会有如下更改:
activity_main.xml
xml 的根节点是
标签, 标签提供数据相关的信息和类,数据绑定通过
@{}
描述说明。xml 文件描述都更改了,inflater dom 解析并不会识别新增的这些标签,那么 DataBinding 是怎么识别的?
/app/build/imtermediates/incremental/mergeDebugResources/stripped.dir/layout/activity_main.xml
/app/build/imtermediates/data_binding_layout_info_type_merge/debug/out/activity_main-layout.xml
false
当我们将项目 build 重新构建时,DataBinding 会将我们的布局 xml 文件拆成了两个 xml 文件:
/app/build/imtermediates/incremental/mergeDebugResources/stripped.dir/layout/activity_main.xml
/app/build/imtermediates/data_binding_layout_info_type_merge/debug/out/activity_main-layout.xml
为了讲解方便,我将前者称为控件数据标记文件,后者称为控件数据查找文件。
DataBinding 将布局中使用了 @{}
的 View 生成 tag 属性标记,去控件数据查找文件就能查找到绑定信息。综合两个 xml 文件就能做到将控件和绑定信息的关系描述清楚。
如上例 TextView 生成了 tag 属性标记为 binding_1,当数据更新时就能通过 binding_1 找到属性 android:text
绑定的数据是 user.name。
或许你会有疑问:标记?查找绑定?那具体又是怎么个标记和查找绑定?
我们继续分析。先写一个简单使用 DataBinding 的 demo:
public class User extends BaseObservable {private String name;private String pwd;public User(String name, String pwd) {this.name = name;this.pwd = pwd;}@Bindablepublic String getName() {return name;}@Bindablepublic String getPwd() {return pwd;}public void setName(String name) {this.name = name;notifyPropertyChanged(BR.name);}public void setPwd(String pwd) {this.pwd = pwd;notifyPropertyChanged(BR.pwd);}
}class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)val binding =DataBindingUtil.setContentView(this, R.layout.activity_main)binding.user = User("vincent", "12345")// binding.textView}
}
上面的 demo 非常简单,创建一个 User 对象,将 User 对象的属性和 xml 中的控件绑定。Activity 对界面的绑定也不是用的 setContentView(),而是通过 DataBindingUtils.setContentView()。
使用 DataBinding 的时候我们可以很方便的通过 binding.textView 的方式获取到控件,它是怎么做到的?DataBindingUtils.setContentView() 到底做了什么事情?
DataBindingUtils.javapublic static T setContentView(@NonNull Activity activity,int layoutId) {return setContentView(activity, layoutId, sDefaultComponent);
}public static T setContentView(@NonNull Activity activity,int layoutId, @Nullable DataBindingComponent bindingComponent) {// 还是调用 Activity 的 setContentView() 填充布局activity.setContentView(layoutId);View decorView = activity.getWindow().getDecorView();ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content);return bindToAddedViews(bindingComponent, contentView, 0, layoutId);
}private static T bindToAddedViews(DataBindingComponent component,ViewGroup parent, int startChildren, int layoutId) {final int endChildren = parent.getChildCount();final int childrenAdded = endChildren - startChildren;if (childrenAdded == 1) {// 如果我们的布局只有一个控件,调用 bind() 绑定final View childView = parent.getChildAt(endChildren - 1);return bind(component, childView, layoutId);} else {// 如果布局有多个控件,循环获取布局的控件,然后 bind() 绑定final View[] children = new View[childrenAdded];for (int i = 0; i < childrenAdded; i++) {children[i] = parent.getChildAt(i + startChildren);}return bind(component, children, layoutId);}
}// DataBinderMapperImpl 是 APT 生成的类
private static DataBinderMapper sMapper = new DataBinderMapperImpl();static T bind(DataBindingComponent bindingComponent, View[] roots,int layoutId) {return (T) sMapper.getDataBinder(bindingComponent, roots, layoutId);
}
DataBindingUtils.setContentView() 通过源码分析,其实还是调用的 Activity 的 setContentView(),然后拿到 DecorView 下的 FrameLayout(android.R.id.content),将我们布局中的每个控件进行绑定。
其中 sMapper 是 APT 生成的类,文件生成在 /app/build/generated/ap_generated_sources/debug/out/com/example/demo/databinding/DataBindingMapperImpl.java
。
DataBindingMapperImpl.javaprivate static final int LAYOUT_ACTIVITYMAIN = 1;private static final SparseIntArray INTERNAL_LAYOUT_ID_LOOKUP = new SparseIntArray(1);static {INTERNAL_LAYOUT_ID_LOOKUP.put(com.example.demo.R.layout.activity_main, LAYOUT_ACTIVITYMAIN);
}@Override
public ViewDataBinding getDataBinder(DataBindingComponent component, View view, int layoutId) {int localizedLayoutId = INTERNAL_LAYOUT_ID_LOOKUP.get(layoutId);if(localizedLayoutId > 0) {final Object tag = view.getTag();if(tag == null) {throw new RuntimeException("view must have a tag");}switch(localizedLayoutId) {case LAYOUT_ACTIVITYMAIN: {// /app/build/imtermediates/incremental/mergeDebugResources/stripped.dir/layout/activity_main.xml// xml 文件的根节点 tagif ("layout/activity_main_0".equals(tag)) {// APT 生成的实现类return new ActivityMainBindingImpl(component, view);}throw new IllegalArgumentException("The tag for activity_main is invalid. Received: " + tag);}}}return null;
}
getDataBinder() 就做了一件事情,根据根布局生成的 tag 标记 layout/activity_main_0 创建对应界面的 ViewDataBinding 即 ActivityMainBindingImpl,在它的构造函数中就做了控件绑定的操作,让我们能够通过 binding.textView
的方式拿到控件:
ActivityMainBindingImpl.javapublic ActivityMainBindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {// 数字 2 表示布局绑定的控件数量this(bindingComponent, root, mapBindings(bindingComponent, root, 2, sIncludes, sViewsWithIds));
}private ActivityMainBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {super(bindingComponent, root, 1, (android.widget.TextView) bindings[1] // 控件绑定);this.mboundView0 = (android.widget.LinearLayout) bindings[0];this.mboundView0.setTag(null);this.textView.setTag(null);setRootTag(root);// listenersinvalidateAll();
}ViewDataBinding.javaprotected static Object[] mapBindings(DataBindingComponent bindingComponent, View root,int numBindings, IncludedLayouts includes, SparseIntArray viewsWithIds) {Object[] bindings = new Object[numBindings];// mapBindings() 把 View 对象都存到 bindings 数组里面// 应用层就能够直接 binding.textView 使用mapBindings(bindingComponent, root, bindings, includes, viewsWithIds, true);return bindings;
}
构造函数中最主要的一句代码是 mapBindings(),该方法将我们布局中的 View 都存到数组中,最终应用层就可以通过 binding.textView 的方式拿到布局中的 View。
我们梳理下 DataBindingUtils.setContentView() 做了什么事情:
通过 Activity 的 setContentView() 加载布局
根据布局根节点的 tag 属性 layout/activity_xxx_0 创建对应布局的 ViewDataBinding
在 ViewDataBinding 创建时遍历布局所有的 View 存到数组中,数组的 View 赋值给 ViewDataBinding 的控件变量。实现可以通过 binding 获取控件 View
DataBinding 使用的是观察者模式,只是这个观察者模式的变种比较大。既然是观察者模式,还是会需要有注册、监听和通知三个操作。那么 DataBinding 是在什么时候开始做注册的?
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)val binding =DataBindingUtil.setContentView(this, R.layout.activity_main)binding.user = User("vincent", "12345")// binding.textView}
}
上面的代码是创建 ActivityMainBindingImpl 后,调用了 setUser() 将我们要提供数据的对象传给了 DataBinding。
ActivityMainBindingImpl.javapublic void setUser(@Nullable com.example.demo.User User) {updateRegistration(0, User);this.mUser = User;synchronized(this) {mDirtyFlags |= 0x1L;}notifyPropertyChanged(BR.user);super.requestRebind();
}
上面的代码虽然很简短,但是却做了几个操作:
updateRegistration():注册监听流程,绑定观察者 observer 和被观察者 observable
mDirtyFlags:数据是否更新标志
super.requestRebind():请求执行界面刷新
因为涉及的类比较多,在分析时我们需要时刻记得区分好观察者和被观察者,否则很容易会出现分析了流程,但是都不知道这些类是用来干嘛的。
ViewDataBinding.java// 存储观察者的数组
private WeakListener[] mLocalFieldObservers;private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {@Overridepublic WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();}
};// localFieldId:每个数据对象都会分配一个数据对象绑定 id
// observable:数据对象 User,被观察者
// CREATE_PROPERTY_LISTENER:用于创建 WeakPropertyListener 和 WeakListener
// WeakListener:持有 DataBinding、数据对象绑定 id、数据对象
protected boolean updateRegistration(int localFieldId, Observable observable) {return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
}private boolean updateRegistration(int localFieldId, Object observable,CreateWeakListener listenerCreator) {...WeakListener listener = mLocalFieldObservers[localFieldId];if (listener == null) {// 第一次获取为 null,走此处的注册过程// listenerCreator 是 CREATE_PROPERTY_LISTENERregisterTo(localFieldId, observable, listenerCreator);return true;}...return true;
}protected void registerTo(int localFieldId, Object observable,CreateWeakListener listenerCreator) {if (observable == null) {return;}WeakListener listener = mLocalFieldObservers[localFieldId];if (listener == null) {// CREATE_PROPERTY_LISTENER.create() 创建 WeakPropertyListener// WeakPropertyListener 会创建 WeakListenerlistener = listenerCreator.create(this, localFieldId);mLocalFieldObservers[localFieldId] = listener;...}// 注册数据监听listener.setTarget(observable);
}
通过分析 updateRegistration() 我们列出几个比较重要信息和区分下观察者和被观察者:
localFieldId:数据对象绑定 id。用于查找存储 WeakListener 的数组索引
observable:数据对象 User,被观察者
WeakPropertyListener:持有 WeakListener
WeakListener:ViewDataBinding、数据对象绑定 id、数据对象的包装类,观察者。一个 WeakListener 对应一个数据对象
源码中 mLocalFieldObservers 虽然是存储 WeakListener 的观察者数组,通过源码分析它只是临时记录用于解除绑定操作,和数据绑定通知 UI 刷新无关,从注册流程角度分析我们可以忽略它的作用。
updateRegistration() 内调用 registerTo(),创建 WeakListener 并且存储到 mLocalFieldObservers 数组中。从这个角度分析,ViewDataBinding 是被观察者。
我们继续看 registerTo() 的 listener.setTarget(observable)
做了什么事情:
private static class WeakPropertyListener extends Observable.OnPropertyChangedCallbackimplements ObservableReference {final WeakListener mListener;public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {// 创建 WeakPropertyListener 的同时创建了 WeakListenermListener = new WeakListener(binder, localFieldId, this);}@Overridepublic WeakListener getListener() {return mListener;}@Overridepublic void addListener(Observable target) {// 注册数据更新监听回调,target 是 User 对象target.addOnPropertyChangedCallback(this);}@Overridepublic void onPropertyChanged(Observable sender, int propertyId) {}...
}private static class WeakListener extends WeakReference {private final ObservableReference mObservable;protected final int mLocalFieldId; // 数据对象绑定 idprivate T mTarget; // 数据对象public WeakListener(ViewDataBinding binder, int localFieldId,ObservableReference observable) {super(binder, sReferenceQueue);mLocalFieldId = localFieldId;mObservable = observable; // WeakPropertyListener}public void setTarget(T object) {unregister();mTarget = object; // 记录数据对象 Userif (mTarget != null) {// 调用 WeakPropertyListener 的 addListenermObservable.addListener(mTarget);}}...
}public class BaseObservable implements Observable {private transient PropertyChangeRegistry mCallbacks;public BaseObservable() {}// OnPropertyChangedCallback 就是 WeakPropertyListener// WeakPropertyListener 持有 WeakListener// WeakListener 保存有 ViewDataBinding、数据对象绑定 id、数据对象@Overridepublic void addOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {synchronized (this) {if (mCallbacks == null) {mCallbacks = new PropertyChangeRegistry();}}mCallbacks.add(callback);}
}public class PropertyChangeRegistry extendsCallbackRegistry {
}public class CallbackRegistry implements Cloneable {// 存储 WeakPropertyListener 的列表private List mCallbacks = new ArrayList();public synchronized void add(C callback) {if (callback == null) {throw new IllegalArgumentException("callback cannot be null");}int index = mCallbacks.lastIndexOf(callback);if (index < 0 || isRemoved(index)) {mCallbacks.add(callback);}}
}
listener.setTarget(observable)
其实就是注册观察者的操作,将 WeakPropertyListener 存储到 CallbackRegistry 的观察者列表。
简单总结下 updateRegistration() 就做了两件事情:
为每一个需要绑定的数据对象提供一个数据对象绑定 id,创建 WeakListener,WeakListener 是 ViewDataBinding、数据对象绑定 id、数据对象 User 的包装类
创建 CallbackRegistry,把它理解为 Observable 被观察者,将 WeakListener 注册到列表存储
为了方便理解,我们用伪代码描述下 updateRegistration():
public class ActivityMainBindingImpl {public void updateRegistration(User user) {registerTo(0, user);} public void registerTo(int localFieldId, User user) {WeakListener listener = new WeakListener(this, localFieldId);listener.setTarget(user);}
}public class WeakListener {private ViewDataBinding binder;private int localFieldId;private User user;public WeakListener(ViewDataBinding binder, int localFieldId) {this.binder = binder;this.localFieldId = localFieldId;}public void setTarget(User user) {user.addOnPropertyChangedCallback(this);}
}public class User extends BaseObservable {// PropertyChangeRegistry/CallbackRegitry 本质上就是对这个观察者列表的操作private List mCallbacks;// 其实就是注册观察者的操作public void addOnPropertyChangedCallback(WeakListener callback) {mCallbacks.add(callback);}
}
具体流程如下:
在上面经过 updateRegistration() 完成了注册观察者的操作后,setUser() 的流程还没结束:
ActivityMainBindingImpl.javapublic void setUser(@Nullable com.example.demo.User User) {updateRegistration(0, User);this.mUser = User;synchronized(this) {mDirtyFlags |= 0x1L;}notifyPropertyChanged(BR.user);super.requestRebind();
}
紧接着修改了 mDirtyFlags,并且调用了 super.requestRebind():
protected void requestRebind() {...if (USE_CHOREOGRAPHER) {mChoreographer.postFrameCallback(mFrameCallback);} else {mUIThreadHandler.post(mRebindRunnable);}
}protected ViewDataBinding(DataBindingComponent bindingComponent, View root, int localFieldCount) {...if (USE_CHOREOGRAPHER) {// 通过编舞者每 16.6ms 接收一个 VSYNC 信号刷新 UImChoreographer = Choreographer.getInstance();mFrameCallback = new Choreographer.FrameCallback() {@Overridepublic void doFrame(long frameTimeNanos) {mRebindRunnable.run();}};} else {mFrameCallback = null;mUIThreadHandler = new Handler(Looper.myLooper());}
}private final Runnable mRebindRunnable = new Runnable() {@Overridepublic void run() {...executePendingBindings();}
};public void executePendingBindings() {if (mContainingBinding == null) {executeBindingsInternal();} else {mContainingBinding.executePendingBindings();}
}private void executeBindingsInternal() {...executeBindings();...
}ActivityMainBindingImpl.java@Override
protected void executeBindings() {long dirtyFlags = 0;synchronized(this) {dirtyFlags = mDirtyFlags;mDirtyFlags = 0;}java.lang.String userName = null;com.example.demo.User user = mUser;// 判断 dirtyFlags 是否有修改if ((dirtyFlags & 0x7L) != 0) {if (user != null) {// read user.nameuserName = user.getName();}}// batch finishedif ((dirtyFlags & 0x7L) != 0) {// 更新 UIandroidx.databinding.adapters.TextViewBindingAdapter.setText(this.textView, userName);}
}
DataBinding 刷新 UI 的方式是通过注册编舞者 Choreographer,每 16.6ms 接收一个 VSYNC 信号,再结合 mDirtyFlags 判断数值是否有修改,如果需要更新在下一个 VSYNC 信号到来时刷新 UI。
你可能有留意到在 setUser() 时我将 notifyPropertyChanged(BR.user)
忽略跳过了,其实是因为首次注册监听绑定时调用这句代码不会处理更新操作。但是我们数据更新通知刷新 UI 就是使用的该方法:
public class User extends BaseObservable {private String name;private String pwd;public User(String name, String pwd) {this.name = name;this.pwd = pwd;}@Bindablepublic String getName() {return name;}@Bindablepublic String getPwd() {return pwd;}public void setName(String name) {this.name = name;// 通知更新 UInotifyPropertyChanged(BR.name);}public void setPwd(String pwd) {this.pwd = pwd;// 通知更新 UInotifyPropertyChanged(BR.pwd);}
}
我们以 setName() 为例子讲解下 notifyPropertyChanged(id) 的原理:
BaseObservable.javaprivate transient PropertyChangeRegistry mCallbacks;public void notifyPropertyChanged(int fieldId) {synchronized (this) {if (mCallbacks == null) {return;}}mCallbacks.notifyCallbacks(this, fieldId, null);
}CallbackRegistry.javapublic synchronized void notifyCallbacks(T sender, int arg, A arg2) {...// sender 是 User// arg 是 BR.namenotifyRecurse(sender, arg, arg2);...
}private void notifyRecurse(T sender, int arg, A arg2) {...// sender 是 User// arg 是 BR.namenotifyRemainder(sender, arg, arg2, remainderIndex);...
}private void notifyRemainder(T sender, int arg, A arg2, int remainderIndex) {if (remainderIndex < 0) {// sender 是 User// arg 是 BR.namenotifyFirst64(sender, arg, arg2);} else {...}
}private void notifyFirst64(T sender, int arg, A arg2) {final int maxNotified = Math.min(Long.SIZE, mCallbacks.size());// sender 是 User// arg 是 BR.namenotifyCallbacks(sender, arg, arg2, 0, maxNotified, mFirst64Removed);
}private void notifyCallbacks(T sender, int arg, A arg2, final int startIndex,final int endIndex, final long bits) {long bitMask = 1;for (int i = startIndex; i < endIndex; i++) {if ((bits & bitMask) == 0) {// sender 是 User// arg 是 BR.name// mCallbacks.get(i) 拿到 BR.name 对应的 WeakPropertyListener// mNotifier 是 PropertyChangeRegistry 的 NOTIFIER_CALLBACKmNotifier.onNotifyCallback(mCallbacks.get(i), sender, arg, arg2);}bitMask <<= 1;}
}
mNotifier 是 PropertyChangeRegistry 通过构造传入的 NOTIFIER_CALLBACK:
CallbackRegistry.javaprivate final NotifierCallback mNotifier;public CallbackRegistry(NotifierCallback notifier) {mNotifier = notifier;
}public class PropertyChangeRegistry extendsCallbackRegistry {private static final CallbackRegistry.NotifierCallback NOTIFIER_CALLBACK = new CallbackRegistry.NotifierCallback() {@Overridepublic void onNotifyCallback(Observable.OnPropertyChangedCallback callback, Observable sender,int arg, Void notUsed) {// callback 是 WeakPropertyListener// sender 是 User// arg 是 BR.namecallback.onPropertyChanged(sender, arg);}};public PropertyChangeRegistry() {super(NOTIFIER_CALLBACK);}
}WeakPropertyListener.javafinal WeakListener mListener;@Override
public void onPropertyChanged(Observable sender, int propertyId) {ViewDataBinding binder = mListener.getBinder();if (binder == null) {return;}Observable obj = mListener.getTarget();if (obj != sender) {return; // notification from the wrong object?}// binder 是 ActivityMainBindingImpl// sender 是 User// propertyId 是 BR.namebinder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
}ViewDataBinding.javaprivate void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {...// mLocalFieldId = 0// object 是 User // fieldId 是 BR.nameboolean result = onFieldChange(mLocalFieldId, object, fieldId);if (result) {// 等待下一次 VSYNC 信号到来时刷新 UIrequestRebind();}
}ActivityMainBindingImpl.java@Override
protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {switch (localFieldId) {case 0 :return onChangeUser((com.example.demo.User) object, fieldId);}return false;
}
private boolean onChangeUser(com.example.demo.User User, int fieldId) {if (fieldId == BR._all) {synchronized(this) {mDirtyFlags |= 0x1L;}return true;}else if (fieldId == BR.name) {synchronized(this) {mDirtyFlags |= 0x2L; // 修改数值,下一个 VSYNC 信号到来时刷新 UI}return true;}return false;
}
根据上面的源码分析,notifyPropertyChanged() 做了以下事情:
根据数据对象绑定 id 从 CallbackRegistry 找到要通知的 WeakPropertyListener
WeakPropertyListener.onPropertyChanged() 拿着 WeakListener,WeakListener 对应一个数据对象,再根据 BR.name 找到 mDirtyFlags 修改数值
如果判断 mDirtyFlags 数据需要更新,则等待下一个 VSYNC 信号到来时执行 UI 刷新
具体流程如下:
该篇文章从布局绑定、注册监听、数据驱动 UI 更新各个流程都做了详细的源码分析,根据上面的内容我们再做对各流程做一个总结梳理。
布局绑定流程 DataBindingUtils.setContentView():
通过 Activity 的 setContentView() 加载布局
根据布局根节点的 tag 属性 layout/activity_xxx_0 创建对应布局的 ViewDataBinding
ViewDataBinding 创建时遍历布局所有的 View 存到数组中,数组的 View 赋值给 ViewDataBinding 的控件变量。实现可以通过 binding 获取控件 View
注册监听流程 updateRegistration():
为每一个需要绑定的数据对象提供一个数据对象绑定 id,创建 WeakListener,WeakListener 是 ViewDataBinding、数据对象绑定 id、数据对象 User 的包装类
创建 CallbackRegistry,把它理解为 Observable,将 WeakListener 注册到观察者列表,完成观察者和被观察者的绑定
UI 刷新流程 requestRebind():
DataBinding 刷新 UI 的方式是通过注册编舞者 Choreographer,每 16.6ms 接收一个 VSYNC 信号,再结合 mDirtyFlags 判断数值是否有修改,如果需要更新在下一个 VSYNC 信号到来时刷新 UI。
数据驱动 UI 更新流程 notifyPropertyChanged():
根据数据对象绑定 id 从 CallbackRegistry 找到要通知的 WeakPropertyListener
WeakPropertyListener.onPropertyChanged() 拿着 WeakListener,WeakListener 对应一个数据对象,再根据 propertyId 找到 mDirtyFlags 修改数值
如果判断 mDirtyFlags 数据需要更新,则等待下一个 VSYNC 信号到来时执行 UI 刷新
我们将所有流程再梳理成伪代码,方便理解:
public class User extends BaseObservable {// PropertyChangeRegistry/CallbackRegitry 本质上就是对这个观察者列表的操作private List mCallbacks;// 注册观察者public void addOnPropertyChangedCallback(WeakListener callback) {mCallbacks.add(callback);}public void setName(String name) {// 数据更新,通知刷新 UInotifyPropertyChanged(BR.name);}public void notifyPropertyChanged(int propertyId) {WeakListener listener = mCallbacks.get(0);int localFieldId = listener.localFieldId;boolean result = listener.binder.onFieldChanged(localFieldId, propertyId);if (result) {// 需要更新 UI,下一个 VSYNC 信号到来时执行 UI 刷新listener.binder.requestRebind();}}
}public class ActivityMainBindingImpl {private User mUser;private int mDirtyFlags;// 注册监听流程public void updateRegistration(User user) {mUser = user;registerTo(0, user);} public void registerTo(int localFieldId, User user) {WeakListener listener = new WeakListener(this, localFieldId);listener.setTarget(user);}// 收到数据更新需要刷新 UI 通知public boolean onFieldChanged(int localFieldId, int propertyId) {switch (localFieldId) {case 0:if (propertyId == BR.name) {// 修改 mDirtyFlags 数值,下一个 VSYNC 信号刷新 UImDirtyFlags |= 0x2L; return true;}}return false;}// 编舞者刷新 UIpublic void requestRebind() {mChoreographer.postFrameCallback(mFrameCallback);}public ActivityMainBindingImpl() {mChoreographer = Choreographer.getInstance();mFrameCallback = new Choreographer.FrameCallback() {@Overridepublic void doFrame(long frameTimeNanos) {executeBindings();}};}public void executeBindings() {if ((mDirtyFlags & 0x2L) != 0) {textView.setText(mUser.getName());}}
}public class WeakListener {public ViewDataBinding binder;public int localFieldId;public WeakListener(ViewDataBinding binder, int localFieldId) {this.binder = binder;this.localFieldId = localFieldId;}// 注册监听,将观察者和被观察者绑定public void setTarget(User user) {user.addOnPropertyChangedCallback(this);}
}