侧边栏壁纸
博主头像
慢行的骑兵博主等级

贪多嚼不烂,欲速则不达

  • 累计撰写 38 篇文章
  • 累计创建 27 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Android Jetpack | DataBinding

慢行的骑兵
2021-09-13 / 0 评论 / 0 点赞 / 912 阅读 / 4,973 字

一.前言

  • 本篇文章主要按照三个方面来讲,使用Databinding之后为什么不需要findViewByIdModel驱动UI的模型是如何设计的View改变是如何驱动Model变化的

二.Databinding简介

2.1.核心思想

  • 当数据发生变化时,UI 自动更新;当用户与 UI 交互时,数据自动同步;

2.2.作用

  • 不需要findViewById;
  • 能承担activity、fragment的部分简单逻辑;
  • 解耦(架构上促进了UI跟逻辑的分离,是 MVVM 的基石);

三.源码分析

  • 我们借助下方代码示例,来分析在前言中所提到的问题,代码如下:
//MainActivity类
public class MainActivity extends AppCompatActivity {
    ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

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

        User user = new User("张三","15");
        binding.setUser(user);
//        binding.setVariable(BR.name,"李四");

    }
}

//User类
public class User extends BaseObservable {
    private String name;
    private String age;


    public User(String name, String age) {
        this.name = name;
        this.age = age;
    }

    @Bindable
    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);

    }

    @Bindable
    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
        notifyPropertyChanged(BR.age);
    }
}

//activity_main.xml
<?xml version="1.0" encoding="utf-8"?>

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="user"
            type="com.jack.databinding.User" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name}" />

        <TextView
            android:id="@+id/tv_age"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.age}" />

    </LinearLayout>
</layout>

3.1.为什么使用databinding之后,不需要做findViewbyId

  • 在分析之前,我们先看databinding生成的2个Java文件和2个xml文件;

    • ActivityMainBindingImpl.java和ActivityMainBinding.java,其中ActivityMainBindingImpl继承自ActivityMainBinding的实现类,ActivityMainBinding继承自ViewDataBinding类(ActivityMainBinding和ViewDataBinding均为抽象类,ViewDataBinding是Datbinding框架中的);
    • activity_main.xml和activity_main-layout.xml;这两份xml文件组合来描述我们所写的xml代码,一份(activity_main.xml)在布局的每一个节点增加了一个TAG,另外一份(activity_main-layout.xml)中TAG跟View有对应关系 & 有 Ex’pressions 标签,该标签描述数据相关的内容(属性对应的内容);
  • ActivityMainBindingImpl.java,参考路径:

xxx\app\build\generated\ap_generated_sources\debug\out\com\jack\databinding\databinding\ActivityMainBindingImpl.java
  • ActivityMainBinding.java,参考路径:
xxx\app\build\generated\data_binding_base_class_source_out\debug\out\com\jack\databinding\databinding\ActivityMainBinding.java
  • activity_main.xml,参考路径和代码:
xxx\build\intermediates\incremental\debug\packageDebugResources\stripped.dir\layout\activity_main.xml
//代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:tag="layout/activity_main_0">

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:tag="binding_1" />

    <TextView
        android:id="@+id/tv_age"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:tag="binding_2" />
</LinearLayout>
  • activity_main-layout.xml,参考路径和代码:
//路径
xxx\app\build\intermediates\data_binding_layout_info_type_merge\debug\mergeDebugResources\out\activity_main-layout.xml
//代码
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Layout directory="layout" filePath="app\src\main\res\layout\activity_main.xml"
    isBindingData="true" isMerge="false" layout="activity_main"
    modulePackage="com.jack.databinding" rootNodeType="android.widget.LinearLayout">
    <Variables name="user" declared="true" type="com.jack.databinding.User">
        <location endLine="7" endOffset="46" startLine="5" startOffset="8" />
    </Variables>
    <Targets>
        <Target tag="layout/activity_main_0" view="LinearLayout">
            <Expressions />
            <location endLine="27" endOffset="18" startLine="10" startOffset="4" />
        </Target>
        <Target id="@+id/tv_name" tag="binding_1" view="TextView">
            <Expressions>
                <Expression attribute="android:text" text="user.name">
                    <Location endLine="19" endOffset="38" startLine="19" startOffset="12" />
                    <TwoWay>false</TwoWay>
                    <ValueLocation endLine="19" endOffset="36" startLine="19" startOffset="28" />
                </Expression>
            </Expressions>
            <location endLine="19" endOffset="41" startLine="15" startOffset="8" />
        </Target>
        <Target id="@+id/tv_age" tag="binding_2" view="TextView">
            <Expressions>
                <Expression attribute="android:text" text="user.age">
                    <Location endLine="25" endOffset="37" startLine="25" startOffset="12" />
                    <TwoWay>false</TwoWay>
                    <ValueLocation endLine="25" endOffset="35" startLine="25" startOffset="28" />
                </Expression>
            </Expressions>
            <location endLine="25" endOffset="40" startLine="21" startOffset="8" />
        </Target>
    </Targets>
</Layout>
  • 分析DataBindingUtil.setContentView(this,R.layout.activity_main)
  //1.入口
  DataBindingUtil.setContentView(this, initContentView())
  
  //2.setContentView    
 public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity, int layoutId) {
        return (T)setContentView(activity, layoutId, sDefaultComponent);
    }

  //3.setContentView  
    public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity, int layoutId, @Nullable DataBindingComponent bindingComponent) {
        activity.setContentView(layoutId);
        View decorView = activity.getWindow().getDecorView();
        ViewGroup contentView = (ViewGroup)decorView.findViewById(16908290);
        return (T)bindToAddedViews(bindingComponent, contentView, 0, layoutId);
    }
  
  //4.bindToAddedViews   
  private static <T extends ViewDataBinding> 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);
          //5.bind
          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);
          }
          //5.bind
          return bind(component, children, layoutId);
      }
  }
  
  //6.1.sMapper是一个成员变量,指向DataBinderMapperImpl,DataBinderMapperImpl是apt自动生成的
  private static DataBinderMapper sMapper = new DataBinderMapperImpl();
  
  //5.bind
  static <T extends ViewDataBinding> T bind(DataBindingComponent bindingComponent, View root,
          int layoutId) {
      //6.2.getDataBinder,会执行DataBinderMapper的getDataBinder,根据多态,执行DataBinderMapperImpl的getDataBinder函数
      return (T) sMapper.getDataBinder(bindingComponent, root, layoutId);
  }
  
//7.DataBinderMapperImpl的getDataBinder函数
  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)) {
            //8.判断tag是否满足条件,执行new ActivityMainBindingImpl的操作
            return new ActivityMainBindingImpl(component, view);
          }
          throw new IllegalArgumentException("The tag for activity_main is invalid. Received: " + tag);
        }
      }
    }
    return null;
  }
  • 查看 ActivityMainBindingImpl类的代码
    public ActivityMainBindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
        //9.mapBindings函数(参数3的值由我们所写的布局来决定的,在ViewDataBinding类中)的调用 & 方法重载
        this(bindingComponent, root, mapBindings(bindingComponent, root, 3, sIncludes, sViewsWithIds));
    }
    private ActivityMainBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
    //10.重载父类构造(即:ActivityMainBinding的构造)
        super(bindingComponent, root, 1
            , (android.widget.TextView) bindings[2]
            , (android.widget.TextView) bindings[1]
            );
        this.mboundView0 = (android.widget.LinearLayout) bindings[0];
        this.mboundView0.setTag(null);
        this.tvAge.setTag(null);
        this.tvName.setTag(null);
        setRootTag(root);
        // listeners
        invalidateAll();
    }
  • ViewDataBinding类的mapBindings函数的作用:将我们写的xml布局中的View找出来存入到数组中,在重载ActivityMainBindingImpl构造时作为参数传递。
  • 分析ActivityMainBinding的构造
protected ActivityMainBinding(Object _bindingComponent, View _root, int _localFieldCount,
    TextView tvAge, TextView tvName) {
  super(_bindingComponent, _root, _localFieldCount);
  this.tvAge = tvAge;
  this.tvName = tvName;
}
  • 此时,我们就可以通过DataBindingUtil.setContentView(this,R.layout.activity_main)得到的对象,进行.tvAge或.tvName得到xml中所定义的View。

  • 总结一下:DataBindingUtil.setContentView 做的事情,将Apt生成的对象new 出来 & 解析生成的XML文件 && 将XML中的View对象在ActivityMainBinding当中进行了存储。从而就需要findViewById了。

3.2.数据驱动UI的模型是如何设计的

  • 这部分我们需要探讨的是,databinding是如何做到,model的改变后,view跟着改变

  • 源码看一轮之后,不建议按照源码的执行流程去分析了,我们得换个角度,如此,才能更快的把握好主体结构;

  • databinding实际上是使用观察者模式来实现的,底层还是View.settext方案来实现View的更新;既然是观察者模式,我们就需要分清楚被观察者和观察者,同时还需要知道如何建立联系的;

3.2.1.被观察者

  • 我们在xml中通过variable设置的type对象就是被观察者,上方案例中的User是被观察者;

3.2.2.观察者

  • 观察者:ViewDataBinding(抽象类,ActivityMainBinding是其子类,也是抽象类,而ActivityMainBinding的具体实现为ActivityMainBindingImpl),之所以认定其是观察者是因为javabean发生变化的时候,最终会触发其executeBindings方法,从而实现View的更新;
public class ActivityMainBindingImpl extends ActivityMainBinding  {
    //...
    public void setUser(@Nullable com.jack.databinding.User User) {
        updateRegistration(0, User);
		 //User被存储到ActivityMainBinding的成员变量mUser中
        this.mUser = User;
        synchronized(this) {
			//在初始化阶段 mDirtyFlags被赋值了 mDirtyFlags = 2 ^ N,N由BR中的数量(总数量 - 1)决定的
            mDirtyFlags |= 0x1L;
        }
        notifyPropertyChanged(BR.user);
        super.requestRebind();
    }
    //...
    @Override
    protected void executeBindings() {
        long dirtyFlags = 0;
        synchronized(this) {
            dirtyFlags = mDirtyFlags;
            mDirtyFlags = 0;
        }
        java.lang.String userName = null;
        java.lang.String userAge = null;
        com.jack.databinding.User user = mUser;
        if ((dirtyFlags & 0xfL) != 0) {
            if ((dirtyFlags & 0xbL) != 0) {
                    if (user != null) {
                        // read user.name
                        userName = user.getName();
                    }
            }
            if ((dirtyFlags & 0xdL) != 0) {
                    if (user != null) {
                        // read user.age
                        userAge = user.getAge();
                    }
            }
        }
        // batch finished
        if ((dirtyFlags & 0xdL) != 0) {
            // api target 1
            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tvAge, userAge);
        }
        if ((dirtyFlags & 0xbL) != 0) {
            // api target 1
            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tvName, userName);
        }
    }
    //...
}
  • 观察者也清楚了,我们现在只需要弄明白被观察者跟观察者是如何建立关联,并且被观察者发生改变,被观察者是如何通知观察者做出相应,即可明白databiding的核心原理。

3.2.3.被观察者和观察者建立关联

  • 这个建立关联的函数为setVariable,如下:
public boolean setVariable(int variableId, @Nullable Object variable)  {
    boolean variableSet = true;
    if (BR.user == variableId) {
        setUser((com.jack.databinding.User) variable);
    }
    else {
        variableSet = false;
    }
        return variableSet;
}
  • 我们就从setVariable开始逐步分析被观察者和观察者之间是如何建立关联的,这里的逻辑会有些绕,因为这里的建立关联跟传统的观察者模式不一样,传统的比较简单,但是这里用了大量的类和接口才真正的建立起关联。所以,这部分的逻辑会有些赋值,不过我们慢慢分析,还是会比较清晰的。我们就以setUser作为入口。
//ActivityMainBindingImpl类中 
//1.步骤1
//---> setUser(@Nullable com.jack.databinding.User User)
//2.步骤2
//---> updateRegistration(0, User);
//3.步骤3
//--->ViewDataBinding类的updateRegistration(int localFieldId, Observable observable)
//4.步骤4	得开始贴详细代码了
//--->updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER)
     
//4.1.先看方法的第三个参数的代码
//CREATE_PROPERTY_LISTENER是ViewDataBinding类中静态的成员变量
//是一个匿名内部类的对象,此时create方法还未被调用
private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
    @Override
    public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
    //这里可以看到WeakPropertyListener中持有viewDataBinding
        return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();
    }
};

//4.2.updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER)
//localFieldId = 0,observable = personInfo
private boolean updateRegistration(int localFieldId, Object observable,
            CreateWeakListener listenerCreator) {
    //...
    
    //mLocalFieldObservers是ViewDataBinding类的成员变量,是一个WeakListener数组
    //mLocalFieldObservers的初始化时机是在ViewDataBinding的构造函数中
    //WeakListener[] mLocalFieldObservers:存储BR中每一个属性 所对应的 监听器
    WeakListener listener = mLocalFieldObservers[localFieldId];
    //此时,listener为null
    if (listener == null) {
        //5.步骤5
        registerTo(localFieldId, observable, listenerCreator);
        return true;
    }
    if (listener.getTarget() == observable) {		
        return false;
    }
    //略...
}

//5.步骤5
protected void registerTo(int localFieldId, Object observable,
        CreateWeakListener listenerCreator) {
    //...
    WeakListener listener = mLocalFieldObservers[localFieldId];
    //此时还是为null,进入if
    if (listener == null) {		
        //5.1.listenerCreator是4.1中的CREATE_PROPERTY_LISTENER
        //此时,create方法调用了,WeakPropertyListener类被创建,listener指向WeakPropertyListener
        listener = listenerCreator.create(this, localFieldId);
        //mLocalFieldObservers[localFieldId] 被赋值
        mLocalFieldObservers[localFieldId] = listener;
        //当主动调用ViewDataBinding的setLifecycleOwner函数时,this.mLifecycleOwner就会有值。如在MainActivity中执行ActivityMainBinding.setLifecycleOwner(this),ViewDataBinding类中的静态内部类OnStartListener就能感知Avtivity的onStart生命周期变化事件(具体代码略);
        if (this.mLifecycleOwner != null) {
                //5.2.点进去查看,调用listener指向WeakPropertyListener的setLifecycleOwner函数,最终调用WeakPropertyListener(结合4.1中的CREATE_PROPERTY_LISTENER就可以知晓)的setLifecycleOwner(内部是一个空实现)
                //listener.setLifecycleOwner对应的是WeakListener类的mObservable(指向的是WeakPropertyListener)成员变量执行setLifecycleOwner函数,即:将this.mLifecycleOwner传递到WeakPropertyListener中,但实际未做任何操作(方法是空实现)
        		listener.setLifecycleOwner(this.mLifecycleOwner);
        }
        //...
    }
    //6.步骤6
    listener.setTarget(observable);
}

//6.步骤6
//执行WeakListener类setTarget方法
private static class WeakListener<T> extends WeakReference<ViewDataBinding> {
    //...

    public void setTarget(T object) {
        unregister();
        mTarget = object;
        if (mTarget != null) {
            //通过上面的CREATE_PROPERTY_LISTENER我们可以知道 
            //mObservable = WeakPropertyListener
            //mTarget = User
            //mObservable在这里是ObservableReference接口,故分析其具体实现类的方法
            //7.步骤7:分析WeakPropertyListener的addListener
            mObservable.addListener(mTarget);
        }
    }

    //...
}

//7.步骤7
private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
        implements ObservableReference<Observable> {
    final WeakListener<Observable> mListener;

    //...

    @Override
    public void addListener(Observable target) {
    	//target = User
    	//调用父类Observable类(具体实现为)的addOnPropertyChangedCallback方法
    	//8.步骤8 	
        target.addOnPropertyChangedCallback(this);
    }

    //...
}


//8.步骤8
public class BaseObservable implements Observable {
	//...
	
    @Override
    public void addOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {
        synchronized (this) {
            if (mCallbacks == null) {
                mCallbacks = new PropertyChangeRegistry();
            }
        }
        //调用了mCallbacks(PropertyChangeRegistry)中的add方法。
        //最终是将OnPropertyChangedCallback添加到一个List集合中(实际上是该接口的实现类-对应WeakPropertyListener)
        //对于集合的添加,需要追踪到PropertyChangeRegistry的父类-CallbackRegistry-的add方法
        //9.步骤9
        mCallbacks.add(callback);
    }
	
	//...
}
//9.步骤9
//PropertyChangeRegistry父类-CallbackRegistry类
private List<C> mCallbacks = new ArrayList<C>();
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);
    }
}
  • 总结一下,步骤1-步骤9所作的事情,观察者ViewDataBinding中有个数组,每一个被观察者对应该数组中一个WeakListener类,WeakListener给被观察者做了一件事情,给被添加了一个接口,该接口最终是被存储到CallbackRegistry类的集合中
  • 建立关系到这里已经完成,但是我们还看不出是如何触发,触发时机上跟传统的观察者模式一样,触发的api是定义在了被观察者中。下面,我们来分析通知观察者的api。

3.2.4.BaseObservable类

  • 通知观察者的api为BaseObservable的notifyPropertyChanged(fieldId)
  • 调用User的setName,会触发notifyPropertyChanged(BR.name)(其它也类似,即User发生变化);
//10.步骤10
public void notifyPropertyChanged(int fieldId) {
    synchronized (this) {
        if (mCallbacks == null) {
            return;
        }
    }
    //11.步骤11
    mCallbacks.notifyCallbacks(this, fieldId, null);
}

//11.步骤11
public synchronized void notifyCallbacks(T sender, int arg, A arg2) {
    mNotificationLevel++;
    //12.步骤12
    notifyRecurse(sender, arg, arg2);
    mNotificationLevel--;
    //...
}

//12.步骤12
private void notifyRecurse(T sender, int arg, A arg2) {
    //13.步骤13
    notifyCallbacks(sender, arg, arg2, startCallbackIndex, callbackCount, 0);
}

//13.步骤13
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) {
        	//步骤14
            //mNotifier的赋值为PropertyChangeRegistry类中的NOTIFIER_CALLBACK
            //这里实际上就是遍历CallbackRegistry类中的mCallbacks的所有对象(实际存储的是WeakPropertyListener),将其作为下方函数的第一个参数进行传递
            mNotifier.onNotifyCallback(mCallbacks.get(i), sender, arg, arg2);
        }
        bitMask <<= 1;
    }
}

//14.步骤14    
public abstract static class NotifierCallback<C, T, A> {
    public abstract void onNotifyCallback(C callback, T sender, int arg, A arg2);
}

public class PropertyChangeRegistry extends CallbackRegistry<OnPropertyChangedCallback, Observable, Void> {
    private static final NotifierCallback<OnPropertyChangedCallback, Observable, Void> NOTIFIER_CALLBACK = new NotifierCallback<OnPropertyChangedCallback, Observable, Void>() {
    //实际调用的位置,PropertyChangeRegistry类中匿名内部类NOTIFIER_CALLBACK对于的onNotifyCallback回调	
        public void onNotifyCallback(OnPropertyChangedCallback callback, Observable sender, int arg, Void notUsed) { 
            //调用Observable类中的OnPropertyChangedCallback的实现类的onPropertyChanged方法
            //15.步骤15
            callback.onPropertyChanged(sender, arg);
        }
    };

    public PropertyChangeRegistry() {
        super(NOTIFIER_CALLBACK);
    }

    public void notifyChange(@NonNull Observable observable, int propertyId) {
        this.notifyCallbacks(observable, propertyId, (Object)null);
    }
}

//15.步骤15:根据多态,会执行WeakPropertyListener的onPropertyChanged
abstract class OnPropertyChangedCallback {
    public abstract void onPropertyChanged(Observable sender, int propertyId);
}

private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
        implements ObservableReference<Observable> {
    //...

	//实际调用
	//15.步骤15
    @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:处理字段修改的过程   
        //16.步骤16
        binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
    }
}
  • 现在可以把步骤1-步骤16联系起来,也就是被观察者和观察者建立了关联,同时model改变后,被观察者发送通知给观察者,最终是回调了ViewDataBinding的handleFieldChange方法,我们只要分析出该方法最终的调用,看具体的操作即可;

3.2.5.ViewDataBinding的handleFieldChange方法

//17.步骤17
private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
    //...
    //onFieldChange的具体实现在ActivityMainBindingImpl中
    //内部最终计算是二进制的&和|操作,若被观察者未发生变化,则不会进入if(即属性不需要更新)
    boolean result = onFieldChange(mLocalFieldId, object, fieldId);
    if (result) {		
    	//分析requestRebind
        //18.步骤18
        requestRebind();
    }
}

//18.步骤18
//条件判断略掉(避免过于深入细节)
protected void requestRebind() {
    if (mContainingBinding != null) {
        mContainingBinding.requestRebind();
    } else {
        final LifecycleOwner owner = this.mLifecycleOwner;
        if (owner != null) {
            Lifecycle.State state = owner.getLifecycle().getCurrentState();
            if (!state.isAtLeast(Lifecycle.State.STARTED)) {
                return; // wait until lifecycle owner is started
            }
        }
        synchronized (this) {
            if (mPendingRebind) {
                return;
            }
            mPendingRebind = true;
        }
        //API16及以上 USE_CHOREOGRAPHER 为 true
        if (USE_CHOREOGRAPHER) {
        	//19.步骤19,API16 及以上 会嵌入到编舞者的执行过程中,最终会触发doFrame回调
            //会执行mRebindRunnable的run方法,即最终跟else语句执行的一样
       		//mFrameCallback的创建在ViewDataBinding的构造函数中
            mChoreographer.postFrameCallback(mFrameCallback);
        } else {
        	//会回调mRebindRunnable的run方法	
            //19.步骤19
            mUIThreadHandler.post(mRebindRunnable);
        }
    }
}

//19.步骤19
this.mRebindRunnable = new Runnable() {
            public void run() {
                synchronized(this) {
                    ViewDataBinding.this.mPendingRebind = false;
                }

                ViewDataBinding.processReferenceQueue();
                if (VERSION.SDK_INT >= 19 && !ViewDataBinding.this.mRoot.isAttachedToWindow()) {
                    ViewDataBinding.this.mRoot.removeOnAttachStateChangeListener(ViewDataBinding.ROOT_REATTACHED_LISTENER);
                    ViewDataBinding.this.mRoot.addOnAttachStateChangeListener(ViewDataBinding.ROOT_REATTACHED_LISTENER);
                } else {
                	//20.步骤20
                    ViewDataBinding.this.executePendingBindings();
                }
            }
        };

//20.步骤20
public void executePendingBindings() {
    if (mContainingBinding == null) {
        //会调用executeBindingsInternal	
        //21.步骤21
        executeBindingsInternal();
    } else {
        mContainingBinding.executePendingBindings();
    }
}

//21.步骤21
private void executeBindingsInternal() {
    //...
    if (!mRebindHalted) {	
        //抽象方法,具体实现在在ActivityMainBindingImpl中查看
        //22.步骤22
        executeBindings();		
        //...
    }
    //...
}

//22.步骤22
//ActivityMainBindingImpl类
protected void executeBindings() {
    long dirtyFlags = 0;
    synchronized(this) {
        dirtyFlags = mDirtyFlags;
        mDirtyFlags = 0;
    }
    java.lang.String userName = null;
    java.lang.String userAge = null;
    com.jack.databinding.User user = mUser;

    if ((dirtyFlags & 0xfL) != 0) {
        if ((dirtyFlags & 0xbL) != 0) {

                if (user != null) {
                    // read user.name
                    userName = user.getName();
                }
        }
        if ((dirtyFlags & 0xdL) != 0) {
                if (user != null) {
                    // read user.age
                    userAge = user.getAge();
                }
        }
    }
    // batch finished
    if ((dirtyFlags & 0xdL) != 0) {
        // api target 1
        androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tvAge, userAge);
    }
    if ((dirtyFlags & 0xbL) != 0) {
        // api target 1
        androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tvName, userName);
    }
}
//TextViewBindingAdapter.setText最终还是View.setText

3.3.View改变是如何驱动Model变化的

  • 我们更改一下xml布局的内容,将text=“@{user.name}改成text=”@={user.name},运行项目,查看ActivityMainBindingImpl类代码
//executeBindings函数
if ((dirtyFlags & 0x8L) != 0) {
    // api target 1
    androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.tvAge, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, tvAgeandroidTextAttrChanged);
    androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.tvName, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, tvNameandroidTextAttrChanged);
}

//匿名内部类
private androidx.databinding.InverseBindingListener tvAgeandroidTextAttrChanged = new androidx.databinding.InverseBindingListener() {
    @Override
    public void onChange() {
        // Inverse of user.age
        //         is user.setAge((java.lang.String) callbackArg_0)
        java.lang.String callbackArg_0 = androidx.databinding.adapters.TextViewBindingAdapter.getTextString(tvAge);
        // localize variables for thread safety
        // user != null
        boolean userJavaLangObjectNull = false;
        // user.age
        java.lang.String userAge = null;
        // user
        com.jack.databinding.User user = mUser;
        userJavaLangObjectNull = (user) != (null);
        if (userJavaLangObjectNull) {
            user.setAge(((java.lang.String) (callbackArg_0)));
        }
    }
};
  • 总结:通过设置监听器的方式来实现的;

四.总结

  • Databinding数据驱动UI的更新的核心我们可以根据下图来做一个总结。如图:
    Model驱动UI改变的流程2
  • 被观察者有一个管家PropertyChangeRegistry mCallbacks,该管家对注册的监听进行管理,监听是间接的持有ViewDatabinding的引用;
  • 当被观察者发生改变,并不是像传递的观察者模式一样,直接持有观察者的引用去进行通知,而是 通知管家,让管家将注册的监听进行全部遍历, 而监听因为间接持有ViewDatabinding的引用,从而可以对观察者进行通知来实现UI的更新。
  • 到此,我们对Databinding的原理和源码分析有了一个很不错的了解 && Databinding在多对多关系的处理上,如:通过WeakListener同时持有被观察者和观察者,通过注册的方式将WeakPropertyListener存储到了CallbackRegistry 的集合中,WeakPropertyListener持有WeakListener引用等方式。有助于对设计类似架构的学习。
0

评论区