一同养成写作习惯!这是我参加「日新计划 4 月更文应战」的第11天,点击查看活动详情。

接下来看一下KeyboardLayoutBindingImpl.java这个类:

d.KeyboardLayoutBindingImpl.java
public class KeyboardLayoutBindingImpl extends KeyboardLayoutBinding  {
    private KeyboardLayoutBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
        super(bindingComponent, root, 5
            , (android.widget.TextView) bindings[1]
            );
        this.mboundView0 = (android.widget.RelativeLayout) bindings[0];
        this.mboundView0.setTag(null);
        this.mboundView2 = (android.widget.ImageView) 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);
        this.mboundView5 = (android.widget.TextView) bindings[5];
        this.mboundView5.setTag(null);
        this.mboundView6 = (android.widget.TextView) bindings[6];
        this.mboundView6.setTag(null);
        this.name.setTag(null);
        setRootTag(root);
        // listeners
        invalidateAll();
    }
    @Override
    public void invalidateAll() {
        synchronized(this) {
                mDirtyFlags = 0x40L;
        }
        requestRebind();
    }
    public void setGuide(@Nullable com.xxx.learn.viewmodel.ViewModel Guide) {
        this.mGuide = Guide;
        synchronized(this) {
            mDirtyFlags |= 0x20L;
        }
        notifyPropertyChanged(BR.guide);
        super.requestRebind();
    }
    @Override
    protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
        switch (localFieldId) {
            case 0 :
                return onChangeGuideRightImageDescription((androidx.databinding.ObservableField<java.lang.String>) object, fieldId);
       ......
    }
    @Override
    protected void executeBindings() {
        ......
        //注册观察者
        updateRegistration(0, guideRightImageDescription);
        ......
        //回调后进行UI更新
        androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView3, guideRightImageDescriptionGet);
        ......
    }
}

该类承继了KeyboardLayoutBinding类,在结构办法内,会调用父类的结构办法,将root view[即对应R.layout.keyboard_layout进行inflate生成的view]传给父类,在Fragment内部的onCreateView()中经过getRoot()返回对应layoutId创立的View,其他办法的逻辑履行会在接下来的数据与UI绑定时进行介绍。

e.KeyboardLayoutBinding.java
public abstract class KeyboardLayoutBinding extends ViewDataBinding {
  @NonNull
  public final TextView name;
  @Bindable
  protected ViewModel mGuide;
  protected KeyboardLayoutBinding(Object _bindingComponent, View _root, int _localFieldCount,
      TextView name) {
    super(_bindingComponent, _root, _localFieldCount);
    this.name = name;
  }
  public abstract void setGuide(@Nullable ViewModel guide);
  @Nullable
  public ViewModel getGuide() {
    return mGuide;
  }
  .......
  .......
}

KeyboardLayoutBinding是个抽象类,承继了ViewDataBinding。

f.ViewDataBinding.java
public abstract class ViewDataBinding extends BaseObservable implements ViewBinding {
    .......
    .......
    private final View mRoot;
    .......
    protected ViewDataBinding(DataBindingComponent bindingComponent, View root, int localFieldCount) {
        mBindingComponent = bindingComponent;
        mLocalFieldObservers = new WeakListener[localFieldCount];
        this.mRoot = root;
        if (Looper.myLooper() == null) {
            throw new IllegalStateException("DataBinding must be created in view's UI Thread");
        }
       .......
    }
    public View getRoot() {
        return mRoot;
    }
    .......
    .......

在创立KeyboardLayoutBindingImpl后,结构办法会一步一步的向上传,终究将root view保存在ViewDataBinding中,然后经过getRoot()获取到view。

四.数据与UI绑定剖析

经过上述剖析能够看到了DataBindingUtil.inflate创立KeyboardLayoutBinding的整个进程,那数据与UI任何绑定的呢?
在KeyboardLayoutBindingImpl的结构办法内,会调用 invalidateAll(),接下来看一下绑定流程:

a.ObservableField进行observe()

DataBinding运用的是观察者形式,ObservableField数据注册观察者是在创立DataBinding的时候在结构办法中就履行了,先创立了对应ObservableField数量的WeakListener数组,然后履行流程如下:
——>invalidateAll()
——>requestRebind()
——>executePendingBindings()
——>executeBindingsInternal()
——> executeBindings()[Impl]
——>updateRegistration(localFieldId, Observable observable)
——>updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER)[创立WeakPropertyListener]
——>registerTo()[将上步中创立的WeakPropertyListener赋值给履行创立的WeakListener对应的数组值]
——>listener.setTarget(observable)
——>WeakPropertyListener.addListener(Observable)
——>Observable.addOnPropertyChangedCallback(this);
经过以上逻辑履行,Observable[ObservableField]注册了OnPropertyChanged callback,假如数据改动后,会回调OnPropertyChanged()办法,流程图如下:

JetPack DataBinding原理分析4

以上便是数据与UI绑定进程,那数据改动后,是如何反应到UI上呢?接下来看一下数据改动后UI更新流程:

b.ObservableField数据改动后UI更新

ObservableFiled数据改动后,终究UI更新履行流程如下:
——>set(value)
——>notifyChange()
——>mCallbacks.notifyCallbacks(this, 0, null)[mCallbacks是PropertyChangeRegistry,经过上述addOnPropertyChangedCallback()参加mCallbacks列表]
——>mNotifier.onNotifyCallback(mCallbacks.get(i), sender, arg, arg2)
——>callback.onPropertyChanged(sender, arg)
——>WeakPropertyListener.onPropertyChanged()
——>handleFieldChange()
——>onFieldChange()——>requestRebind()—–>……
——>executeBindings()[Impl]
在ObservableField数据改动后,终究会调用到Impl类里面的executeBindings()来更新UI,流程图如下:

JetPack DataBinding原理分析4

以上便是数据改动后UI更新的整个流程。

五.BindingAdapter

DataBinding供给了BindingAdapter这个注解用于支持自定义特点,或者是修正原有特点。注解值可所以已有的 xml 特点,例如 android:src、android:text等,也能够自定义特点然后在 xml 中运用。

例如,对于一个TextView ,希望在某个变量值发生改动时,能够动态改动显现的文字,此刻就能够经过 BindingAdapter来实现。

需求先定义一个静态办法,为之添加 BindingAdapter 注解,注解值是为TextView控件自定义的特点名,而该静态办法的两个参数能够这样来理解:当TextView控件的 step特点值发生改动时,DataBinding 就会将TextView实例以及新的step值传递给setProperty() 办法,从而能够依据此动态来改动TextView的相关特点。

<TextView
     android:layout_width="200dp"
     android:layout_height="50dp"
     android:layout_below="@+id/name"
     android:layout_centerHorizontal="true"
     android:layout_marginTop="400dp"
     android:gravity="center"
     android:textStyle="bold"
     app:step="@{guide.step}"/>

BindingAdapter实现如下:

import android.util.Log;
import android.widget.TextView;
import androidx.databinding.BindingAdapter;
//能够独自写一个类,一致处理所有运用BindingAdapter注解的控件 
public class ViewBinding {
    @BindingAdapter(value = {"app:step"})
    public static void setProperty(TextView textView, int step) {
        Log.e("Seven", "step is: " + step);
        //能够依据step来设置textView的特点,例如改动文字,设置宽高等...
        textView.setText(xxx);
    }
    @BindingAdapter(value = {"app:url"})
    public static void updateImg(ImageView imageView, String url) {
        Glide.with(imageView.getContext()).load(url).into(imageView);
    }
}