从DataBinding源码理解Databinding工作过程

原文地址: 从DataBinding源码理解Databinding工作过程

摘要

前几天突然就开始看Databinding,之前在上家公司,最后一个项目中使用过这个技术,相似的技术我接触过得还有Butter Knife,但是显然没有DataBinding功能强大,而且还是Google官方推出的,在功能和兼容性上,都要更胜一筹。

之前项目中,只是学习了怎么使用DataBinding这个技术,但是并没有深入理解,这样一个很蛋疼的问题就是:项目如果能正常运行,那么没有问题,但是一旦出现问题,你可能连编译器里面的错误都看不明白,更何况去解决问题。所以我最近几天重新学习了一下DataBinding。而且是从基础的使用方法重新学习的。(没办法,都忘了。)但是今天咱们不介绍具体使用,想要了解使用方法的可以直接去看官方文档,或者看我最近翻译的几篇Blog。(我其实还是比较推荐直接去看官方文档,简单直接好用)

下面我们就进入今天的主题:Databinding到底是怎么实现双向数据绑定的?

DataBinding生成的代码介绍

项目在buildhou,如果使用了Databinding, 那么会由DataBinding compiler生成ActivityMainBindingImpl.java,ActivityMainBinding.java,BR.java,DataBinderMapperImpl.java等代码,咱们主要看这四个类,数据和方法的绑定都是在这里。

ActivityMainBinding和ActivityMainBindingImpl

位置: app/build/generated/data_binding_base_class_source_out/debug/dataBindingGenBaseClassesDebug/out/com/example/databindingpractise/databinding/ActivityMainBinding.java

app/build/generated/source/apt/debug/com/example/databindingpractise/databinding/ActivityMainBindingImpl.java

在我们的MainActivity中,我们使用:DataBindingUtil.setContentView(this, R.layout.activity_main);方法获得一个ViewDataBinding对象,这是编译器通过layout和绑定viewModel生成的,用于将数据和方法绑定到layout中

public abstract class ActivityMainBinding extends ViewDataBinding {
  @NonNull
  public final TextView textView;

  @NonNull
  public final UpAndDownChoiceLayoutBinding upanddown;

  @Bindable
  protected MainPresenter mPresenter;

  @Bindable
  protected MainViewModel mViewModel;

  @Bindable
  protected UpDownChoicePresenter mUpDownPresenter;

  @Bindable
  protected UpDownChoiceViewModel mUpDownviewModel;

  ....
}
public class ActivityMainBindingImpl extends ActivityMainBinding  {

    ...
    // views
    @NonNull
    private final android.widget.LinearLayout mboundView0;
    @NonNull
    private final android.widget.Button mboundView2;
    @NonNull
    private final android.widget.CheckBox mboundView3;
    
   
    
  ...
}

可以看到:ActivityMainBindingImpl是继承自ActivityMainBinding

  1. ActivityMainBinding
    • 持有含有id的View的引用
    • 持有绑定的类的引用
  2. ActivityMainBindingImpl
    • 持有没有id的View的引用
    • 具体实现了绑定

BR

位置:app/build/generated/source/apt/debug/com/example/databindingpractise/BR.java

public class BR {
  public static final int _all = 0;

  public static final int presenter = 1;

  public static final int upDownviewModel = 2;

  public static final int viewModel = 3;

  ...
}

BR文件储存了VM的id, 功能与R文件类似

DataBinderMapperImpl

public class DataBinderMapperImpl extends DataBinderMapper {
  ....

  @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: {
          if ("layout/activity_main_0".equals(tag)) {
            return new ActivityMainBindingImpl(component, view);
          }
          throw new IllegalArgumentException("The tag for activity_main is invalid. Received: " + tag);
        }
      }
    }
    return null;
  }
  ...
  
}

这个类主要是提供了从布局文件layoutId到ViewDataBinding类对象的映射,主要是用于在加载Layout返回对应的ViewDataBinding对象。

初始化

在这个模块,我们通过查看ViewDataBinding源码,来了解DataBinding是如何将activity_main.layout上的View实例引用保存在对应的ActivityMainBindingActivityMainBindingImpl上的。

我们看一下在MainActivity中执行:

dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

内部进行了什么操作。

进入DataBindingUtil.setContentView

public 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(layoutId);
        View decorView = activity.getWindow().getDecorView();
        ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content);
        return bindToAddedViews(bindingComponent, contentView, 0, layoutId);
}

可以看到,其实内部还是调用了我们原来使用的activity.setContentView(layoutId);填充布局,并拿到了content布局,并传入bindToAddedViews()方法:

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) {
            final View childView = parent.getChildAt(endChildren - 1);
            return bind(component, childView, layoutId);
        } else {
            final View[] children = new View[childrenAdded];
            for (int i = 0; i < childrenAdded; i++) {
                children[i] = parent.getChildAt(i + startChildren);
            }
            return bind(component, children, layoutId);
        }
}

判断布局是否有多个子布局,如果有则遍历存入View数组,最后调用不同参数的bind方法

static  T bind(DataBindingComponent bindingComponent, View root,int layoutId) {
        return (T) sMapper.getDataBinder(bindingComponent, root, layoutId);
}

最后调用DataBinderMapperImpl中的getDataBinder()方法, 获得对应Layout的VIewDataBinding类实例

接下来我们看看,是如何将Layout中的View赋值到ViewDataBinding中的引用:

public ActivityMainBindingImpl(@Nullable android.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
        this(bindingComponent, root, mapBindings(bindingComponent, root, 5, sIncludes, sViewsWithIds));
}
    private ActivityMainBindingImpl(android.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
        super(bindingComponent, root, 2
            , (android.widget.TextView) bindings[1]
            , (com.example.databindingpractise.databinding.UpAndDownChoiceLayoutBinding) bindings[4]
            );
        this.mboundView0 = (android.widget.LinearLayout) bindings[0];
        this.mboundView0.setTag(null);
        this.mboundView2 = (android.widget.Button) bindings[2];
        this.mboundView2.setTag(null);
        this.mboundView3 = (android.widget.CheckBox) bindings[3];
        this.mboundView3.setTag(null);
        this.textView.setTag(null);
        setRootTag(root);
        // listeners
        invalidateAll();
}

当实例化ActivityMainBindingImpl时,我们主要看mapBindings()方法,这个方法将会把layout中的view 存入数组中bindings[]

protected static Object[] mapBindings(DataBindingComponent bindingComponent, View root,
            int numBindings, IncludedLayouts includes, SparseIntArray viewsWithIds) {
        Object[] bindings = new Object[numBindings];
        mapBindings(bindingComponent, root, bindings, includes, viewsWithIds, true);
        return bindings;
}

然后调用同名方法,由于这个方法比较长,我们分成三部分来看:

  1. 从View的tag中获取缓存,防止多次初始化

    
    private static void mapBindings(DataBindingComponent   bindingComponent, View view, Object[] bindings, IncludedLayouts includes, SparseIntArray viewsWithIds, boolean isRoot) {
        ...
            final int indexInIncludes;
            final ViewDataBinding existingBinding = getBinding(view);
            if (existingBinding != null) {
                return;
            }
        ...
        
    }
        
    
    static ViewDataBinding getBinding(View v) {
            if (v != null) {
                return (ViewDataBinding) v.getTag(R.id.dataBinding);
            }
            return null;
    }
    
  2. 将view储存在bindings数组内,分为三种情况:

    1. 根布局,tag以layout开头;
    2. 设置@{}的,tag以binding开头
    3. 设置了id的view
    private static void mapBindings(DataBindingComponent bindingComponent, View view, Object[] bindings, IncludedLayouts includes, SparseIntArray viewsWithIds,boolean isRoot) {
            ...
            Object objTag = view.getTag();
            final String tag = (objTag instanceof String) ? (String) objTag : null;
            boolean isBound = false;
            if (isRoot && tag != null && tag.startsWith("layout")) {
                final int underscoreIndex = tag.lastIndexOf('_');
                if (underscoreIndex > 0 && isNumeric(tag, underscoreIndex + 1)) {
                    final int index = parseTagInt(tag, underscoreIndex + 1);
                    if (bindings[index] == null) {
                        bindings[index] = view;
                    }
                    indexInIncludes = includes == null ? -1 : index;
                    isBound = true;
                } else {
                    indexInIncludes = -1;
                }
            } else if (tag != null && tag.startsWith(BINDING_TAG_PREFIX)) {
                int tagIndex = parseTagInt(tag, BINDING_NUMBER_START);
                if (bindings[tagIndex] == null) {
                    bindings[tagIndex] = view;
                }
                isBound = true;
                indexInIncludes = includes == null ? -1 : tagIndex;
            } else {
                // Not a bound view
                indexInIncludes = -1;
            }
            if (!isBound) {
                final int id = view.getId();
                if (id > 0) {
                    int index;
                    if (viewsWithIds != null && (index = viewsWithIds.get(id, -1)) >= 0 &&
                            bindings[index] == null) {
                        bindings[index] = view;
                    }
                }
            }
        ....
    }
    
  3. 第三部分判断根布局是不是ViewGroup,如果是则遍历根布局,并判断子View是不是include的,如果是的话,则使用DataBindingUtil.bind进行递归;如果不是include,则直接使用mapBindings进行递归。

通过这三个步骤,递归得到最后的bindings[],如果设置了id的,就将view变量设置为public,这样就避免了findViewById的代码。

这种方式从性能上比findViewById高效,因为databinding只需要遍历一次view树,而findViewById多次调用会遍历多次。

private ActivityMainBindingImpl(android.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
        super(bindingComponent, root, 2
            , (android.widget.TextView) bindings[1]
            , (com.example.databindingpractise.databinding.UpAndDownChoiceLayoutBinding) bindings[4]
            );
        this.mboundView0 = (android.widget.LinearLayout) bindings[0];
        this.mboundView0.setTag(null);
        this.mboundView2 = (android.widget.Button) bindings[2];
        this.mboundView2.setTag(null);
        this.mboundView3 = (android.widget.CheckBox) bindings[3];
        this.mboundView3.setTag(null);
        this.textView.setTag(null);
        setRootTag(root);
        // listeners
        invalidateAll();
    }

最后通过setRootTag()方法将View缓存起来。

调用invalidateAll()方法,更新布局,这个方法我们在初始化绑定中讲。

这样我们ActivityMainBindingActivityMainBindingImpl中View引用都对应上View对象了。

初始化绑定

初始化绑定使用如下代码:

dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
dataBinding.setVariable(BR.viewModel, mainViewModel);
//
dataBinding.setViewModel(mainViewMOdel);

上面两个绑定方式其实本质上一致的,最后调用的方法都是 setViewModel()

@Override
public boolean setVariable(int variableId, @Nullable Object variable)  {
        boolean variableSet = true;
        if (BR.viewModel == variableId) {
            setViewModel(
            (com.example.databindingpractise.viewModel.MainViewModel) variable);
        }
        else {
            variableSet = false;
        }
            return variableSet;
}

我们主要看一下setViewModel()方法:

public void setViewModel(@Nullable com.example.databindingpractise.viewModel.MainViewModel ViewModel) {
        this.mViewModel = ViewModel;
        synchronized(this) {
            mDirtyFlags |= 0x20L;
        }
        notifyPropertyChanged(BR.viewModel);
        super.requestRebind();
}

mDirtyFlags用于表示哪个属性发生变化,notifyPropertyChanged(BR.viewModel),顾名思义,是发出viewModel数据变化的通知。看看requestRebind是干什么的:

protected void requestRebind() {
        if (mContainingBinding != null) {
            mContainingBinding.requestRebind();
        } else {
            synchronized (this) {
                if (mPendingRebind) {
                    return;
                }
                mPendingRebind = true;
            }
            if (mLifecycleOwner != null) {
                Lifecycle.State state = mLifecycleOwner.getLifecycle().getCurrentState();
                if (!state.isAtLeast(Lifecycle.State.STARTED)) {
                    return; // wait until lifecycle owner is started
                }
            }
            if (USE_CHOREOGRAPHER) {
                mChoreographer.postFrameCallback(mFrameCallback);
            } else {
                mUIThreadHandler.post(mRebindRunnable);
            }
        }
}

mContainingBinding当include子布局的时候,该属性不为空;mPendingRebind属性表示,是否正在绑定,如果是就直接返回;mLigecyeleOwner对象可用于追踪View的生命周期,如果不为空,且不为start状态,直接return;最后然后根据api版本做了点不同的处理,16及以上的,会往mChoreographer发一mFrameCallback;否则直接往UI线程发一个mRebindRunnable。其实这里俩个分支的结果基本一致,mChoreographer会在界面刷新时执行mRebindRunnableChoreographer是api16后引入的用于解决UI卡顿的,当收到VSYNC(定时中断)时,在doFrame里去执行相应的操作。

我们再看看mRebindRUnnable里面做了什么:

    /**
     * Runnable executed on animation heartbeat to rebind the dirty Views.
     */
    private final Runnable mRebindRunnable = new Runnable() {
        @Override
        public void run() {
            synchronized (this) {
                mPendingRebind = false;
            }
            processReferenceQueue();

            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();
        }
    };

mPendingRebind置为false;

processReferenceQueue(),移除ViewDataBindings中存的weakListener

/**
* Polls sReferenceQueue to remove listeners on ViewDataBindings that have been collected.
*/
private static void processReferenceQueue() {
        Reference ref;
        while ((ref = sReferenceQueue.poll()) != null) {
            if (ref instanceof WeakListener) {
                WeakListener listener = (WeakListener) ref;
                listener.unregister();
            }
        }
 }

如果api19及以上时,判断rootView是否attach到window上,如果没有的话,则对这个attach的状态进行监听。最终都会执行executePendingBindings():

/**
* Evaluates the pending bindings, updating any Views that have expressions bound to
* modified variables. This must be run on the UI thread.
*/
public void executePendingBindings() {
    if (mContainingBinding == null) {
        executeBindingsInternal();
    } else {
        mContainingBinding.executePendingBindings();
    }
}

继而调用executeBindingsInternal()方法。

private void executeBindingsInternal() {
        if (mIsExecutingPendingBindings) {
            requestRebind();
            return;
        }
        if (!hasPendingBindings()) {
            return;
        }
        mIsExecutingPendingBindings = true;
        mRebindHalted = false;
        if (mRebindCallbacks != null) {
            mRebindCallbacks.notifyCallbacks(this, REBIND, null);

            // The onRebindListeners will change mPendingHalted
            if (mRebindHalted) {
                mRebindCallbacks.notifyCallbacks(this, HALTED, null);
            }
        }
        if (!mRebindHalted) {
            executeBindings();
            if (mRebindCallbacks != null) {
                mRebindCallbacks.notifyCallbacks(this, REBOUND, null);
            }
        }
        mIsExecutingPendingBindings = false;
}

hasPendingBindings方法返回是否有数据需要绑定,如果当前没有需要需要绑定的数据,则返回不处理。接下来通知所有的RebindCallbackRebindCallback可以通过ActivityMainBinding.addOnRebindCallback设置。RebindCallback里可以把mRebindHalted置为true,以终止后面的executeBindings()方法。如果被终止了,同样HALTED事件也会通知给所有的RebindCallback

executeBindings()是一个抽象的方法,具体实现在编译时生成的ActivityMainBindingImpl里。

由于代码很多,我们也分成两部分:

  1. 将View中的值与viewModel中的值做绑定,并设置监听值的变化和View变化

    protected void executeBindings() {
            long dirtyFlags = 0;
            synchronized(this) {
                dirtyFlags = mDirtyFlags;
                mDirtyFlags = 0;
            }
            android.databinding.ObservableField viewModelName = null;
            
            java.lang.String viewModelNameGet = null;
            com.example.databindingpractise.viewModel.MainViewModel viewModel = mViewModel;
    
                   
            if ((dirtyFlags & 0x62L) != 0) {
    
                    if (viewModel != null) {
                        // read viewModel.name
                        viewModelName = viewModel.name;
                    }
                    updateRegistration(1, viewModelName);
    
                    if (viewModelName != null) {
                        // read viewModel.name.get()
                        viewModelNameGet = viewModelName.get();
                    }
            }
           
            if ((dirtyFlags & 0x62L) != 0) {
                // api target 1
    
                android.databinding.adapters.TextViewBindingAdapter.setText(this.textView, viewModelNameGet);
            }
            if ((dirtyFlags & 0x40L) != 0) {
                // api target 1
    
                android.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.textView, (android.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (android.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (android.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, textViewandroidTextAttrChanged);
            }
            
        }
    
  2. 将Layout中的事件监听动作与对应的viewModel方法绑定

protected void executeBindings() {
    if ((dirtyFlags & 0x44L) != 0) {
                if (presenter != null) {
                    // read presenter::onCheckedChanged
                    presenterOnCheckedChangedAndroidWidgetCompoundButtonOnCheckedChangeListener = (((mPresenterOnCheckedChangedAndroidWidgetCompoundButtonOnCheckedChangeListener == null) ? (mPresenterOnCheckedChangedAndroidWidgetCompoundButtonOnCheckedChangeListener = new OnCheckedChangeListenerImpl()) : mPresenterOnCheckedChangedAndroidWidgetCompoundButtonOnCheckedChangeListener).setValue(presenter));
                    // read presenter::changeName
                    presenterChangeNameAndroidViewViewOnClickListener = (((mPresenterChangeNameAndroidViewViewOnClickListener == null) ? (mPresenterChangeNameAndroidViewViewOnClickListener = new OnClickListenerImpl()) : mPresenterChangeNameAndroidViewViewOnClickListener).setValue(presenter));
                }
        }
     // batch finished
     if ((dirtyFlags & 0x44L) != 0) {
            // api target 1            this.mboundView2.setOnClickListener(presenterChangeNameAndroidViewViewOnClickListener);
            android.databinding.adapters.CompoundButtonBindingAdapter.setListeners(this.mboundView3, (android.widget.CompoundButton.OnCheckedChangeListener)presenterOnCheckedChangedAndroidWidgetCompoundButtonOnCheckedChangeListener, (android.databinding.InverseBindingListener)null);
        }
}

事件与方法的绑定这里就不说了,上述代码基本已经很清晰的展示了,我们主要分析一下ViewModel上值的变化,他是通过updateRegistration(1, viewModelName);方法实现的:

protected boolean updateRegistration(int localFieldId, Observable observable) {
        return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
}

这里面传入同名方法的第三个参数需要我们注意一下:

private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
        @Override
        public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
            return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();
        }
};

private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
            implements ObservableReference {
        final WeakListener mListener;

        public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
            mListener = new WeakListener(binder, localFieldId, this);
        }

        @Override
        public WeakListener getListener() {
            return mListener;
        }

        @Override
        public void addListener(Observable target) {
            target.addOnPropertyChangedCallback(this);
        }

        @Override
        public void removeListener(Observable target) {
            target.removeOnPropertyChangedCallback(this);
        }

        @Override
        public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
        }

        @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.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
        }
 }
 
private static class WeakListener extends WeakReference {
    private final ObservableReference mObservable;
    protected final int mLocalFieldId;
    private T mTarget;

    public WeakListener(ViewDataBinding binder, int localFieldId,
            ObservableReference observable) {
        super(binder, sReferenceQueue);
        mLocalFieldId = localFieldId;
        mObservable = observable;
    }

    // …… 
}

从上面知道CREATE_PROPERTY_LISTENER是一个CreateWeakListener对象,CreateWeakListener.create()能得到WeakPropertyListenerWeakPropertyListener内有变量WeakListenerWeakListener持有ViewDataBinding以及Observable(即VM)。

我们接着上面看看updateRegistration里面的事情:

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;
}

先从mLocalFieldObservers[]取localFieldId对应的WeakListener,如果为null的话,就调用registerTo()进行注册;如果不为空,而且与之前注册过的不一致的话,则重新注册。那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;
    }
    listener.setTarget(observable);
}

registerTo把CreateWeakListener存储在mLocalFieldObservers里面。

这样一来V和VM的联系就通过ViewDatabinding建立起来了。V内有ViewDatabinding,而ViewDatabinding里持有各个View的引用。ViewDataBinding有VM的变量,而VM内的PropertyChangeRegistry监听实则为WeakPropertyListenerWeakListener能获取到ViewDatabinding

VM变化如何通知View

我们知道,如果要达到VM变化时自动绑定到View上,有下面俩种方式:

  1. 继承自BaseObservable,在getter上增加@Bindable注解,在setter里增加代码notifyPropertyChanged(BR.xxx)
  2. 无需继承,需要将属性替换为Observable类,例如ObservableIntObservableField等。
    /**
     * Notifies listeners that all properties of this instance have changed.
     */
    public void notifyChange() {
        synchronized (this) {
            if (mCallbacks == null) {
                return;
            }
        }
        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
     * BR to be used as fieldId.
     *
     * @param fieldId The generated BR id for the Bindable field.
     */
    public void notifyPropertyChanged(int fieldId) {
        synchronized (this) {
            if (mCallbacks == null) {
                return;
            }
        }
        mCallbacks.notifyCallbacks(this, fieldId, null);
    }

不同的是,一个回调的方法是notifyChange(), 一个回调的方法是notifyPropertyChanged(),不过最后都是通过mCallbacks.notifyCallbacks()返回。

然后,这个监听是在绑定的时候做的设定:

当调用listener.setTarget(observable)时,其实是设置了viewModel的监听事件:

@Override
public void addListener(Observable target) {
   target.addOnPropertyChangedCallback(this);
}

V的变化如何同步到VM

这个相对就简单一下了,是直接对对应的View设置setTextWatcher方法

if ((dirtyFlags & 0x40L) != 0) {
            // api target 1

            android.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.textView, (android.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (android.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (android.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, textViewandroidTextAttrChanged);
        

总结

这篇文章主要跟根据源码来熟悉DataBinding是如何双向绑定数据和方法在Layout上的,在弄清楚这一套逻辑之后,个人觉得DataBinding感觉是通过一种语法规则,将绑定数据和方法自动化,省却了很多需要人为的重复的工作,例如findViewByIdsetOnClickListener等等,让我们能有更多的精力专注于逻辑控制。值得一提的是,使用Databinding很容易构造出MVVM模式的代码。

参考文献:DataBinding源码解析

你可能感兴趣的:(从DataBinding源码理解Databinding工作过程)