一同养成写作习惯!这是我参加「日新计划 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()办法,流程图如下:
以上便是数据与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,流程图如下:
以上便是数据改动后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);
}
}