虽然没有开通专栏之前已经在挖金投稿过了这篇文章,但是我打算写一个关于android data binding库的一系列的文章,为了完整性,我还是在这里重新发布一遍。如果之前已经看过这android data binding 实践之:ViewDataBinding,那么可以忽略下面的内容,如果你喜欢的话可以收藏也可以点赞哦!
在前面的文章中,我简单的介绍了data binding当中的注解的使用,今天主要介绍ViewDataBinding的核心逻辑的实现。
使用过data binding的应该都知道,在编译之后,这个库会为我们生成两种java文件。
BR.java:
这个文件主要是给我们在XML文件中每个标签设置的variable以及被Bindable注解的属性添加一个静态的int类型的索引,在以后对这些variable进行操作的时候都可以使用这个索引id作为参数。
ViewDataBinding的相应的子类:
每一个绑定的XML布局文件都会生成一个以该布局文件名称作为前缀(默认情况下)的ViewDataBinding的相应的子类。在这个文件中主要的处理逻辑主要包括:
- 自动化view管理
- 用户事件监听处理
- 变量管理
- data binding逻辑流
自动化view管理
当我们在XML布局文件中,设置了View的"android:id"属性之后,在生成的ViewDataBinding子类当中会生成一个声明为 public final 的属性值,属性的名称就是我们定义的id的值。而对于那些没有被设置ID的view则会声明为 private final 。因此当我们给view设置了id之后可以不必再自己声明和初始化这些view。
首先XML布局声明如下
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="user"
type="net.uni_unity.databindingdemo.model.ObserVableUser"/>
<variable
name="activity"
type="net.uni_unity.databindingdemo.SecondActivity"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="@{user.firstName}"/>
...
<Button
android:onClick='@{()->activity.onViewClick("click")}'
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="ListenerBinding"/>
</LinearLayout>
</layout>在生成的ViewDataBinding子类中,我们会发现:
// views
public final android.widget.Button btn1;
public final android.widget.Button btn2;
private final android.widget.LinearLayout mboundView0;
private final android.widget.TextView mboundView1;
private final android.widget.TextView mboundView2;
private final android.widget.TextView mboundView3;
private final android.widget.TextView mboundView4;
public SecondActivityBinding(android.databinding.DataBindingComponent bindingComponent, View root) {
...
this.btn1 = (android.widget.Button) bindings[5];
this.btn1.setTag(null);
this.btn2 = (android.widget.Button) bindings[6];
this.btn2.setTag(null);
this.mboundView0 = (android.widget.LinearLayout) bindings[0];
this.mboundView0.setTag(null);
this.mboundView1 = (android.widget.TextView) bindings[1];
this.mboundView1.setTag(null);
this.mboundView2 = (android.widget.TextView) bindings[2];
this.mboundView2.setTag(null);
this.mboundView3 = (android.widget.TextView) bindings[3];
this.mboundView3.setTag(null);
this.mboundView4 = (android.widget.TextView) bindings[4];
this.mboundView4.setTag(null);
...
}这样我们就可以直接在activity当中使用这些声明为public的view了,只要为每个view添加上id之后,连一大堆的"findViewById()"的方法都不用我们去写了。
事件处理(Event Handling)
data binding可以让我们通过定义一些表达式处理从view分发的事件,比如点击事件之类的。事件的属性名字基本由java的listener方法的名字控制(当然也有其他复杂的事件例外)。比如View.OnLongClickListener 拥有一个 onLongClick() 的方法,所以这个事件对应的属性名称就是 android:onLongClick。我们有下面两种方式处理对应的事件。
Method References
使用示例
首先定义我们的事件处理方法
public class SecondActivity extends AppCompatActivity {
...
private void bindData(SecondActivityBinding binding){
ObserVableUser user=new ObserVableUser("firstName","lastName","observable",11);
binding.setUser(user);
binding.setPresenter(this);
}
public void simpleClick(View view){
Log.d("MethodReference","MethodReference click");
}
}然后是在我们的布局文件中通过调用表达式进行绑定
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="presenter"
type="net.uni_unity.databindingdemo.SecondActivity"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:onClick="@{presenter::simpleClick}"
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="MethodReference"/>
</LinearLayout>
</layout>使用解析
关于Method References的详细介绍,我们可以参考官网当中的描述Method References。这里简单总结一下关键的内容:
- 与在XML文件中定义属性“android:onClick”,然后在我们对应的activity中定义onClick()方法类似,我们可以通过自定义一个方法,然后在XML中绑定该方法的调用表达式,完成事件的绑定。但是不同的是,我们的表达式是在编译期就被处理的,所以一旦我们表达式调用的方法不存在的话或者方法签名不正确的话就会出现编译异常
非常关键的一点,我们 自己定义的方法的方法签名必须与实际的listener回调方法的签名保持一致 (即方法的参数类型与个数要一致),否则我们将会在编译期得到这样的编译错误
java.lang.RuntimeException: Found data binding errors.
/ data binding error msg:Listener class android.view.View.OnClickListener with method onClick did not match signature of any method presenter::simpleClick file:/DataBindingDemo/app/src/main/res/layout/second_activity.xml loc:42:31 - 42:52 \ data binding errorXML文件中绑定的表达式是在编译期就被处理掉,如果我们希望在事件响应的时候再进行处理,就可以使用下面的 Listener Bindings 的方法
ViewDataBinding当中的实现
当我们使用 Method References 处理事件的时候,data binding library回在 ViewDataBinding 生成下面的处理代码
// Listener Stub Implementations
public static class OnClickListenerImpl implements android.view.View.OnClickListener{
private net.uni_unity.databindingdemo.SecondActivity value;
public OnClickListenerImpl setValue(net.uni_unity.databindingdemo.SecondActivity value) {
this.value = value;
return value == null ? null : this;
}
@Override
public void onClick(android.view.View arg0) {
this.value.simpleClick(arg0);
}
}上面的代码可以发现,在 ViewDataBinding 中生成了一个实现了 android.view.View.OnClickListener 事件接口的静态内部类,而这个类主要做了两件事情
- 添加了一个 setValue() 的方法。方法的参数其实就是我们自己定义的事件回调方法所在的类的实例。在上面的实例中,我们定义了一个 simpleClick() ,因为我把方法定义在了在activity里面,所以对应的就是activity的实例。)
- 实现了 onClick() 的方法。而方法的实现里面其实调用的就是我们自己定义的那个回调方法。
而我们会在生成的ViewDataBinding的子类中看到一个 OnClickListenerImpl mAndroidViewViewOnCl 的filed的声明,而这个对象的初始化就放在了binding调用链的最后里面。如下所示:
@Override
protected void executeBindings() {
...
if ((dirtyFlags & 0x28L) != 0) {
if (activity != null) {
// read activity::simpleClick
androidViewViewOnCli = (((mAndroidViewViewOnCl == null) ? (mAndroidViewViewOnCl = new OnClickListenerImpl()) : mAndroidViewViewOnCl).setValue(activity));
}
}
...
}从上面的代码中我们可以看出,使用 Method References 的方式处理回调事件,其实就是对我们平常一直使用的 OnClickListener 的一层简单的包装而已。
Listener Bindings
通过使用 Listener Bindings 的方式,我们可以在事件回调的时候再触发我们所绑定的 lambda 表达式。它的使用方法与 Method References 相似,但是这种方式却可以使我们具备调用已经被编译成了字节码的表达式的能力。
值得注意的是,这个特性只有在Gradle2.0及以后的版本当中才被支持。
使用示例
首先定义我们的事件处理方法
public void onViewClick(String tag){
Log.d("ListenerBinding","ListenerBinding "+tag);
}然后是在我们的布局文件中通过lambda表达式进行绑定
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="presenter"
type="net.uni_unity.databindingdemo.SecondActivity"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:onClick='@{()->presenter.onViewClick("click")}'
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="ListenerBinding"/>
</LinearLayout>
</layout>使用解析
关于Listener Bindings的详细介绍,我们可以参考官网当中的描述Listener Bindings.这里还是总结一下使用的关键点:
- 在上面的 Method References 中我们提及到,自定义的方法签名必须与listener的回调方法的签名保持一致。但是 Listener Bindings 却没有这样的要求。它只要求 自定义的方法的返回值与listener的回调方法的返回值保持一致 即可。
- 在定义的 lambda 表达式中,我们可以选择是否传入view参数,而且参数的名称也是可以自己随意定义的。
ViewDataBinding当中的实现
Listener Bindings 在ViewDataBinding当中的实现要比 Method References 稍微复杂一点。
首先,也是对 android.view.View.OnClickListener 进行了一层包裹,生成了一个实现了点击事件监听接口的类
public final class OnClickListener implements android.view.View.OnClickListener {
final Listener mListener;
final int mSourceId;
public OnClickListener(Listener listener, int sourceId) {
mListener = listener;
mSourceId = sourceId;
}
@Override
public void onClick(android.view.View callbackArg_0) {
mListener._internalCallbackOnClick(mSourceId , callbackArg_0);
}
public interface Listener {
void _internalCallbackOnClick(int sourceId , android.view.View callbackArg_0);
}
}这个类里面关键的点就是内部又定义了一个Listener的接口,并且点击事件的最终调用的就是接口里面的 _internalCallbackOnClick() 方法。那么根据上面的 Method References 的实现套路,我们大概能猜到我们的 ViewDataBinding 应该实现了上面的接口。👇
public class SecondActivityBinding extends android.databinding.ViewDataBinding implements android.databinding.generated.callback.OnClickListener.Listener {
...
public final void _internalCallbackOnClick(int sourceId , android.view.View callbackArg_0) {
// localize variables for thread safety
// presenter
net.uni_unity.databindingdemo.SecondActivity presenter = mPresenter;
// presenter != null
boolean presenterObjectnull = false;
presenterObjectnull = (presenter) != (null);
if (presenterObjectnull) {
presenter.onViewClick("click");
}
}
...
}在上面的代码中 presenter.onViewClick("click") 方法里面的字符串是我们的lambda表达式里面传入的参数。
那么我们是在哪个地方完成了view的监听事件绑定的呢?
首先,我们在生成的 ViewDataBinding 子类里面的构造方法看到了如下的初始化代码
public SecondActivityBinding(android.databinding.DataBindingComponent bindingComponent, View root) {
super(bindingComponent, root, 3);
final Object[] bindings = mapBindings(bindingComponent, root, 7, sIncludes, sViewsWithIds);
...
this.btn2 = (android.widget.Button) bindings[6];
this.btn2.setTag(null);
// listeners
mCallback1 = new android.databinding.generated.callback.OnClickListener(this, 1);
invalidateAll();
}上面的 mCallback1 初始化之后调用了 invalidateAll() 这个方法,关于这个方法的调用链我们会在后面继续分析,我们这里先把结果说出来,在调用链的最后会触发 executeBindings() 的调用,而在这个方法的里面我们能够发现:
@Override
protected void executeBindings() {
...
if ((dirtyFlags & 0x20L) != 0) {
// api target 1
this.btn2.setOnClickListener(mCallback1);
}
...
}看到这里,大概每个看官都能够明白了,其实Listener Bindings 和 Method References 非常相似,两个都是对原来的listener的接口实现进行了一层包裹,最终调用在 onClick() 事件里面调用我们自己方法。
上面还有一个问题被忽略了,那就是在实例化 mCallback 的时候,需要传入一个称为 sourceId 的值。关于这个值是怎么回事,我们会在以后的 android data binding实践之:注解处理流剖析 一文中再进行详细的讨论。
变量管理
关于这一块的内容,有一篇文章分析的挺好的,感兴趣的可以看一下。
Android Data Binding 系列(二) -- Binding与Observer实现原理
我们在XML布局文件中绑定的每一个variable都会在对应的ViewDataBinding实现子类中生成一个对应的setter方法。不管对应的variable是一个简单的Java bean对象,还是一个实现了observable的对象,抑或是使用了ObservableField的对象,基本上都是一样的(存在细微不同,下面会提及)。看下面代码的实际例子:
//这段代码显示的是我们在XML文件中绑定的一个publicUser对象生成的setter方法
//这里的publicUser是一个集成了observable的对象
public void setPublicUser(net.uni_unity.databindingdemo.model.PublicUser publicUser) {
//更新监听的注册
//在这个方法里面,确保不重复监听,会先移除再添加观察监听
//对于ObservableField,这个监听注册的更新是放在executeBindings()方法当中的,也即requestRebind()调用链的最后一步
updateRegistration(1, publicUser);
this.mPublicUser = publicUser;
//通过mDirtyFlags标识变量(关于这个mDirtyFlags,自己不是很理解)
synchronized(this) {
mDirtyFlags |= 0x2L;
}
//接口回调,通知属性发生了变化
notifyPropertyChanged(BR.publicUser);
//requestRebind()方法之后会经过一系列的引用链之后执行再次绑定,实现view的刷新
super.requestRebind();
}从上面的分析可以知道,data binding当中任意的一个属性的改变,基本都会经历下面的几个步骤:
- 监听的注册(对应的是updateRegistration()方法)
- 基本的赋值操作
- 锁定mDirtyFlags标识变量
- 监听接口回调(对应的是notifyPropertyChanged()方法)
- 执行重新绑定(requestRebind()方法)
监听的注册
上面的 updateRegistration(int, Observable)最终调用的是另一个一个私有的方法 updateRegistration(int, Object,CreateWeakListener listenerCreator) ,代码如下所示:
protected boolean updateRegistration(int localFieldId, Observable observable) {
return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
}
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;
}
// target是我们的监听接口的监听的对象,当前后监听对象一致的时候,无需任何操作
if (listener.getTarget() == observable) {
return false;//nothing to do, same object
}
// 否则线取消原来的监听,再进行重新注册新的监听
unregisterFrom(localFieldId);
registerTo(localFieldId, observable, listenerCreator);
return true;
}在上面的调用过程中,传入了一个名为 CREATE_PROPERTY_LISTENER 的CreateWeakListener对象,而它在ViewDataBinding定义的如下:
private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
@Override
public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();
}
};CREATE_PROPERTY_LISTENER 只是一个实例化的接口对象,在registerTo()方法中,通过接口对象的create()方法可以创建出一个弱引用的WeakListener对象,这个对象来自于 WeakPropertyListener 的field值。
registerTo()方法主要是将listener绑定到Observable对象上。绑定时,会调用listener.setTarget()将Observable对象传给WeakPropertyListener实例,然后,WeakPropertyListener会为Observable对象添加OnPropertyChangedCallback。
代码如下所示:
//ViewDataBinding中的监听注册入口方法
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;
}
listener.setTarget(observable);
}
//WeakListener定义
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);
mLocalFieldId = localFieldId;
mObservable = observable;
}
// 将Observable对象传递给WeakPropertyListener的实例mObservable
// 因为WeakPropertyListener实现了ObservableReference的接口
// 在新建WeakListener的实例的时候,其实是获取WeakPropertyListener的mListener(参考前面的CREATE_PROPERTY_LISTENER)
public void setTarget(T object) {
unregister();
mTarget = object;
if (mTarget != null) {
mObservable.addListener(mTarget);
}
}
...
}
private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback implements ObservableReference<Observable> {
final WeakListener<Observable> mListener;
public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
mListener = new WeakListener<Observable>(binder, localFieldId, this);
}
@Override
public WeakListener<Observable> getListener() {
return mListener;
}
@Override
public void addListener(Observable target) {
target.addOnPropertyChangedCallback(this);
}
@Override
public void removeListener(Observable target) {
target.removeOnPropertyChangedCallback(this);
}
@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?
}
// 注册的监听接口的回调最后会来到这个地方
// 而handleFieldChange()的方法实现会在编译期生成的ViewDataBinding当中实现
binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
}
}
//addOnPropertyChangedCallback()是由BaseObservable里面定义的,如下所示:
public class BaseObservable implements Observable {
...
@Override
public synchronized void addOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
if (mCallbacks == null) {
mCallbacks = new PropertyChangeRegistry();
}
mCallbacks.add(callback);
}
@Override
public synchronized void removeOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
if (mCallbacks != null) {
mCallbacks.remove(callback);
}
}
...
}前面涉及到的接口和方法比较多,下面附上一张关于这一块的类图:

前面说了那么多,终于把监听接口注册完了。那么接下来继续看一下回调的流程
监听接口回调
设置或更新Observable对象(setter方法被调用)的时候,都会调用 notifyPropertyChanged() 或者 notifyChange() 通知更新。代码如下:
/**
* Notifies listeners that all properties of this instance have changed.
*/
public synchronized void notifyChange() {
if (mCallbacks != null) {
mCallbacks.notifyCallbacks(this, 0, null);
}
}
/**
* Notifies listeners that a specific property has changed. The getter for the property
* that changes should be marked with {@link Bindable} to generate a field in
* <code>BR</code> to be used as <code>fieldId</code>.
*
* @param fieldId The generated BR id for the Bindable field.
*/
public void notifyPropertyChanged(int fieldId) {
// mCallbacks 是 PropertyChangeRegistry对象,在addOnPropertyChangedCallback 时实例化
// 如果注册了Observable对象监听,那么mCallbacks不为null
if (mCallbacks != null) {
mCallbacks.notifyCallbacks(this, fieldId, null);
}
}
//PropertyChangeRegistry继承了CallbackRegistry,
//上面的notifyCallbacks()调用回进入CallbackRegistry的notifyCallbacks()
public class CallbackRegistry<C, T, A> implements Cloneable {
...
private void notifyCallbacks(T sender, int arg, A arg2, int startIndex, int endIndex, long bits) {
long bitMask = 1L;
for(int i = startIndex; i < endIndex; ++i) {
if((bits & bitMask) == 0L) {
// mNotifier 是实例化PropertyChangeRegistry时创建的
// mNotifier 即CallbackRegistry.NotifierCallback
this.mNotifier.onNotifyCallback(this.mCallbacks.get(i), sender, arg, arg2);
}
bitMask <<= 1;
}
}
...
}
// onNotifyCallback()是CallbackRegistry.NotifierCallback的一个抽象方法
// 它的实现是在PropertyChangeRegistry当中
public class PropertyChangeRegistry extends CallbackRegistry<Observable.OnPropertyChangedCallback, Observable, Void> {
...
private static final CallbackRegistry.NotifierCallback<Observable.OnPropertyChangedCallback, Observable, Void> NOTIFIER_CALLBACK = new CallbackRegistry.NotifierCallback<Observable.OnPropertyChangedCallback, Observable, Void>() {
@Override
public void onNotifyCallback(Observable.OnPropertyChangedCallback callback, Observable sender,int arg, Void notUsed) {
// callback 是为Observable对象添加的OnPropertyChangedCallback,即WeakPropertyListener
// 而上面的WeakPropertyListener最后回在onPropertyChanged()中调用生成的ViewDataBinding的子类的handleFieldChange()
callback.onPropertyChanged(sender, arg);
}
};
...
}经过上面的几番周折,终于完成了监听接口的回调操作。
在我们的变量的setter方法当中还有一个环节就是调用 requestRebind() 。这个方法的内容,我放在下面的data binding逻辑流当中进行阐述。
data binding逻辑流
在我们编译期生成的ViewDataBinding的生成子类的构造方法中,首先会通过 mapBindings() 完成绑定的view的统计,紧接着就是对相应的view进行初始化。构造方法的最后会有一个 invalidateAll() 的调用。代码如下所示:
@Override
public void invalidateAll() {
synchronized(this) {
mDirtyFlags = 0x20L;
}
// 这个方法也是我们调用setter方法更新属性值的时候会调用的重新绑定的操作的方法
requestRebind();
}
protected void requestRebind() {
synchronized (this) {
if (mPendingRebind) {
return;
}
mPendingRebind = true;
}
// 这里是根据系统版本的不同之行的不同的页面刷新策略
// USE_CHOREOGRAPHER = SDK_INT >= 16
if (USE_CHOREOGRAPHER) {
mChoreographer.postFrameCallback(mFrameCallback);
} else {
mUIThreadHandler.post(mRebindRunnable);
}
}
// 上面这个我们着重关注mRebindRunnable的实现,它是我们执行重新绑定的核心任务
private final Runnable mRebindRunnable = new Runnable() {
@Override
public void run() {
synchronized (this) {
mPendingRebind = false;
}
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
// Nested so that we don't get a lint warning in IntelliJ
if (!mRoot.isAttachedToWindow()) {
// Don't execute the pending bindings until the View
// is attached again.
mRoot.removeOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER);
mRoot.addOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER);
return;
}
}
executePendingBindings();
}
};
// 显然上面经过一番检查之后,最终调用了executePendingBindings(),这就是真正的大boss所在了
/**
* Evaluates the pending bindings, updating any Views that have expressions bound to
* modified variables. This <b>must</b> be run on the UI thread.
*/
public void executePendingBindings() {
if (mIsExecutingPendingBindings) {
requestRebind();
return;
}
if (!hasPendingBindings()) {
return;
}
mIsExecutingPendingBindings = true;
mRebindHalted = false;
//mRebindCallbacks是一个CallbackRegistry对象的实例,这里是一个重新绑定事件的回调的集合
//CallbackRegistry这个对象看完前面的应该感觉到很熟悉,我们的监听接口回调也是跟它的一个子类打交道的
if (mRebindCallbacks != null) {
mRebindCallbacks.notifyCallbacks(this, REBIND, null);
// The onRebindListeners will change mPendingHalted
if (mRebindHalted) {
mRebindCallbacks.notifyCallbacks(this, HALTED, null);
}
}
if (!mRebindHalted) {
// 这是在编译期的生成子类当中会实现的一个方法
// 在这个方法里面完成了view的点击事件绑定、variable的赋值、view的操作(包括ObservableField对象的监听注册)等布局页面与数据之间的绑定操作
executeBindings();
if (mRebindCallbacks != null) {
mRebindCallbacks.notifyCallbacks(this, REBOUND, null);
}
}
mIsExecutingPendingBindings = false;
}
// 根据前面的分析,我们的mRebindCallbacks通过notifyCallbacks()完成回调的通知
// 下面看一下重绑回调实现的CallbackRegistry.NotifierCallbac对象
private static final CallbackRegistry.NotifierCallback<OnRebindCallback, ViewDataBinding, Void>
REBIND_NOTIFIER = new NotifierCallback<OnRebindCallback, ViewDataBinding, Void>() {
@Override
public void onNotifyCallback(OnRebindCallback callback, ViewDataBinding sender, int mode,
Void arg2) {
switch (mode) {
case REBIND:
if (!callback.onPreBind(sender)) {
sender.mRebindHalted = true;
}
break;
case HALTED:
callback.onCanceled(sender);
break;
case REBOUND:
callback.onBound(sender);
break;
}
}
};data binding的逻辑流还有很多的细节,这里暂时不做具体的展开,只是掌握基本的事件传递的流程。相信仔细看上面的的代码的注释的话,基本都能够掌握到这个逻辑流的线索。
写在后面
写这篇分析前前后后看了n多遍ViewDataBinding这个类以及编译期生成的相应子类,代码量不算轻,好几次都把自己搞得一脸懵逼,而且也知道该用怎样的逻辑去表述自己的理解。最后自己将里面的内容进行了分块,大概就像上面阐述的那样。
另外这篇文章也有几个问题没有解决:
- dirtyFlags这个变量的使用
- 关于view data binding当中的事件回调机制没有进行仔细的展开,即CallbackRegistry的具体实现细节和逻辑,这个之后后另外再开一篇文章进行阐述
- data binding的逻辑流过程中会存在很多细节的问题也没有继续展开
关于上面这几个问题,对于逻辑流的细节,我觉得只要我们能够掌握主线,基本上在使用的过程中估计也能明白不少问题了。
另外关于这个data binding库的注解处理也是非常的漂亮的,自己会再另外一篇文章进行简要的阐述。
上面可能还有不少表述不清的地方,欢迎有兴趣的一起讨论,一起学习。感谢你宝贵的时间阅读这篇文章!