jetpack分析3:databinding分析

70 阅读7分钟

问题思考

  • databinding是怎么生成xml对象类呢?
  • 为啥我在xml设置的tag不生效呢
  • databinding如何实现数据自动刷新呢?

1. 如何生成布局对应的binding对象

  我们show一波基本写法

activity_main.xml
// 通用写法
 <data>
    <variable
        name="mainVm"
        type="com.wqg.wqgdatabdingandviewmodel.MainVm" />
</data>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
     <TextView
        android:id="@+id/tv1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{mainVm.name}"
        android:textSize="20sp"
        tools:text="tv1"/>
    <TextView
        android:layout_marginTop="20dp"
        tools:text="tv2"
        android:textSize="20sp"
        android:id="@+id/tv2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{mainVm.pwd}"/>

    <TextView
        android:layout_marginTop="20dp"
        tools:text="tv3"
        android:textSize="20sp"
        android:id="@+id/tv3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{mainVm.nameF}"/>
    <TextView
        android:layout_marginTop="20dp"
        tools:text="tv4"
        android:textSize="20sp"
        android:id="@+id/tv4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{mainVm.pwdF}"/>

    <EditText
        android:id="@+id/et1"
        android:layout_marginTop="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@={mainVm.name}"
        android:hint="双向绑定1"/>

    <EditText
        android:id="@+id/et2"
        android:layout_marginTop="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@={mainVm.nameF}"
        android:hint="双向绑定2"/>
</LinearLayout>

  编译之后,/app/build/intermediates/data_binding_layout_info_type_merge/debug/out下面拷贝生成了一份activity_main-layout.xml   从下可以看到,他会先针对所有控件都给了一个Taggets的标签,跟布局的设置tag=layout/activity_main_0,其他控件的tag=binding_数字。这就一个坑,你如果手动在xml设置这个TAG是无效的。

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.wqg.wqgdatabdingandviewmodel" rootNodeType="android.widget.LinearLayout">
    <Variables name="mainVm" declared="true" type="com.wqg.wqgdatabdingandviewmodel.MainVm">
        <location endLine="9" endOffset="60" startLine="7" startOffset="8" />
    </Variables>
    <Targets>
        <Target tag="layout/activity_main_0" view="LinearLayout">
            <Expressions />
            <location endLine="68" endOffset="18" startLine="13" startOffset="4" />
        </Target>
        <Target id="@+id/tv1" tag="binding_1" view="TextView">
            <Expressions>
                <Expression attribute="android:text" text="mainVm.name">
                    <Location endLine="23" endOffset="40" startLine="23" startOffset="12" />
                    <TwoWay>false</TwoWay>
                    <ValueLocation endLine="23" endOffset="38" startLine="23" startOffset="28" />
                </Expression>
            </Expressions>
            <location endLine="25" endOffset="29" startLine="19" startOffset="8" />
        </Target>
        <Target id="@+id/tv2" tag="binding_2" view="TextView">
            <Expressions>
                <Expression attribute="android:text" text="mainVm.pwd">
                    <Location endLine="33" endOffset="39" startLine="33" startOffset="12" />
                    <TwoWay>false</TwoWay>
                    <ValueLocation endLine="33" endOffset="37" startLine="33" startOffset="28" />
                </Expression>
            </Expressions>
            <location endLine="33" endOffset="41" startLine="26" startOffset="8" />
        </Target>
        <Target id="@+id/tv3" tag="binding_3" view="TextView">
            <Expressions>
                <Expression attribute="android:text" text="mainVm.nameF">
                    <Location endLine="42" endOffset="41" startLine="42" startOffset="12" />
                    <TwoWay>false</TwoWay>
                    <ValueLocation endLine="42" endOffset="39" startLine="42" startOffset="28" />
                </Expression>
            </Expressions>
            <location endLine="42" endOffset="43" startLine="35" startOffset="8" />
        </Target>
        <Target id="@+id/tv4" tag="binding_4" view="TextView">
            <Expressions>
                <Expression attribute="android:text" text="mainVm.pwdF">
                    <Location endLine="50" endOffset="40" startLine="50" startOffset="12" />
                    <TwoWay>false</TwoWay>
                    <ValueLocation endLine="50" endOffset="38" startLine="50" startOffset="28" />
                </Expression>
            </Expressions>
            <location endLine="50" endOffset="42" startLine="43" startOffset="8" />
        </Target>
        <Target id="@+id/et1" tag="binding_5" view="EditText">
            <Expressions>
                <Expression attribute="android:text" text="mainVm.name">
                    <Location endLine="57" endOffset="41" startLine="57" startOffset="12" />
                    <TwoWay>true</TwoWay>
                    <ValueLocation endLine="57" endOffset="39" startLine="57" startOffset="29" />
                </Expression>
            </Expressions>
            <location endLine="58" endOffset="33" startLine="52" startOffset="8" />
        </Target>
        <Target id="@+id/et2" tag="binding_6" view="EditText">
            <Expressions>
                <Expression attribute="android:text" text="mainVm.nameF">
                    <Location endLine="65" endOffset="42" startLine="65" startOffset="12" />
                    <TwoWay>true</TwoWay>
                    <ValueLocation endLine="65" endOffset="40" startLine="65" startOffset="29" />
                </Expression>
            </Expressions>
            <location endLine="66" endOffset="33" startLine="60" startOffset="8" />
        </Target>
    </Targets>
</Layout>

  以上我们看到了databinding重新拷贝了一份xml,为啥?其实很好理解,android 本身不知道<layout>这个标签的,这玩意是databinding玩的。相当它要解析原来xml data标签和我们真正的布局

  接着我们看下如何生成我们要的databinding布局对象

class MainActivity : AppCompatActivity() {

    private val mVm = MainVm()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main) //从这里开始玩

        binding.mainVm = mVm

        mVm.name = "我是name 1"
        mVm.pwd = "我是pwd  1"
        mVm.nameF.set("我是nameF 1")
        mVm.pwdF.set("我是pwdF 1")
    }
}

class MainVm: ViewModel() {

    var name: String? = null

    var pwd : String? = null


    // 第二种方式
    val nameF : ObservableField<String> by lazy { ObservableField<String>() }
    val pwdF : ObservableField<String> by lazy { ObservableField<String>() }


    val nameF2 = ObservableField("我是双向绑定nameF2")
    val pwdF2  = ObservableField("我是双向绑定pwdF2")

    //-------------------------------------
    var count = ObservableField(0)

}
开始跟上DataBindingUtil.java下面的setContentView了
public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity,int layoutId, @Nullable DataBindingComponent bindingComponent) {
    // 回到原来的setcontentView
    activity.setContentView(layoutId);
    View decorView = activity.getWindow().getDecorView();
    ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content);
    // 重点关注
    return bindToAddedViews(bindingComponent, contentView, 0, layoutId);
}

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

static <T extends ViewDataBinding> T bind(DataBindingComponent bindingComponent, View[] roots,int layoutId) {
    // 核心代码
    return (T) sMapper.getDataBinder(bindingComponent, roots, layoutId);
}

  先看看sMapper 这个是什么鬼东西,再看看getDataBinder到底是干啥的

//DataBindingUtil.java
private static DataBinderMapper sMapper = new DataBinderMapperImpl();

//再看看DataBinderMapperImpl.java
public class DataBinderMapperImpl extends MergedDataBinderMapper {
  DataBinderMapperImpl() {
  //是不是有熟悉的味道了,看到我们自己的包名了
    addMapper(new com.wqg.wqgdatabdingandviewmodel.DataBinderMapperImpl());
  }
}
回到我们之前的问题,sMapper.getDataBinder(bindingComponent, roots, layoutId);自己根据接口实现,最后回到MergedDataBinderMapper.java下面的getDataBinder

public class MergedDataBinderMapper extends DataBinderMapper {

    @Override
    public ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View view,
            int layoutId) {
        // 会通过遍历的方式,前面我们也看到了这个子对象DataBinderMapperImpl
        for(DataBinderMapper mapper : mMappers) {
            ViewDataBinding result = mapper.getDataBinder(bindingComponent, view, layoutId);
            if (result != null) {
                return result;
            }
        }
        if (loadFeatures()) {
            return getDataBinder(bindingComponent, view, layoutId);
        }
        return null;
    }

}

public class DataBinderMapperImpl extends DataBinderMapper {
  private static final int LAYOUT_ACTIVITYMAIN = 1;

  private static final SparseIntArray INTERNAL_LAYOUT_ID_LOOKUP = new SparseIntArray(1);

  static {
    INTERNAL_LAYOUT_ID_LOOKUP.put(com.wqg.wqgdatabdingandviewmodel.R.layout.activity_main, LAYOUT_ACTIVITYMAIN);
  }

  @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: {
        // 看到这个鬼东西了吗?是不是有点熟悉的味道,没错,就是那味,我们前面生成根布局给它设置对应的tag
          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;
  }

  从上面的代码,我们找到了ActivityMainBindingImpl。接着我们看下它干了啥。

public class ActivityMainBindingImpl extends ActivityMainBinding  {
    public ActivityMainBindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
        // mapBindings重点代码
        this(bindingComponent, root, mapBindings(bindingComponent, root, 7, sIncludes, sViewsWithIds));
    }
    
    // 之前xml的tag全部都给弄成null了,所有的控件都存到了bindings数组
    private ActivityMainBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
        super(bindingComponent, root, 2
            , (android.widget.EditText) bindings[5]
            , (android.widget.EditText) bindings[6]
            , (android.widget.TextView) bindings[1]
            , (android.widget.TextView) bindings[2]
            , (android.widget.TextView) bindings[3]
            , (android.widget.TextView) bindings[4]
            );
        this.et1.setTag(null);
        this.et2.setTag(null);
        this.mboundView0 = (android.widget.LinearLayout) bindings[0];
        this.mboundView0.setTag(null);
        this.tv1.setTag(null);
        this.tv2.setTag(null);
        this.tv3.setTag(null);
        this.tv4.setTag(null);
        setRootTag(root);
        // listeners
        invalidateAll();
    }
    
    // 控件都存到数组里面
    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;
    }
    
    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;
        }
        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;
                }
            }
        }

        if (view instanceof  ViewGroup) {
            final ViewGroup viewGroup = (ViewGroup) view;
            final int count = viewGroup.getChildCount();
            int minInclude = 0;
            for (int i = 0; i < count; i++) {
                final View child = viewGroup.getChildAt(i);
                boolean isInclude = false;
                if (indexInIncludes >= 0 && child.getTag() instanceof String) {
                    String childTag = (String) child.getTag();
                    if (childTag.endsWith("_0") &&
                            childTag.startsWith("layout") && childTag.indexOf('/') > 0) {
                        // This *could* be an include. Test against the expected includes.
                        int includeIndex = findIncludeIndex(childTag, minInclude,
                                includes, indexInIncludes);
                        if (includeIndex >= 0) {
                            isInclude = true;
                            minInclude = includeIndex + 1;
                            final int index = includes.indexes[indexInIncludes][includeIndex];
                            final int layoutId = includes.layoutIds[indexInIncludes][includeIndex];
                            int lastMatchingIndex = findLastMatching(viewGroup, i);
                            if (lastMatchingIndex == i) {
                                bindings[index] = DataBindingUtil.bind(bindingComponent, child,
                                        layoutId);
                            } else {
                                final int includeCount =  lastMatchingIndex - i + 1;
                                final View[] included = new View[includeCount];
                                for (int j = 0; j < includeCount; j++) {
                                    included[j] = viewGroup.getChildAt(i + j);
                                }
                                bindings[index] = DataBindingUtil.bind(bindingComponent, included,
                                        layoutId);
                                i += includeCount - 1;
                            }
                        }
                    }
                }
                if (!isInclude) {
                    mapBindings(bindingComponent, child, bindings, includes, viewsWithIds, false);
                }
            }
        }
    }
}

  贴那么多代码,稍微总结下,上面也就是告诉我们所有的控件tag变成了null并都存放到了数组里面(所以你在xml设置tag它是不生效的)。

   其次DataBinderMapperImpl.getDataBinder()通过根布局的tag生成ActivityMainBindingImpl,这也是我们最终想要的xml对应databinding的具体实现类

2. 传入的observer如何监听刷新

   先看下我们XML设置VM,如何刷新

ActivityMainBindingImpl.java

public void setMainVm(@Nullable com.wqg.wqgdatabdingandviewmodel.MainVm MainVm) {
    this.mMainVm = MainVm;
    synchronized(this) {
        mDirtyFlags |= 0x4L;
    }
    notifyPropertyChanged(BR.mainVm); // 添加到监听的地方
    super.requestRebind(); // 刷新数据
}

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;
        }
        if (USE_CHOREOGRAPHER) {
            mChoreographer.postFrameCallback(mFrameCallback);
        } else {
            mUIThreadHandler.post(mRebindRunnable);
        }
    }
}

   接着来看下notifyPropertyChanged(BR.mainVm);。从下面代码可以看出来他是要回调刷新,重点看addOnPropertyChangedCallback,反查下发现BaseObservableField构造函数就引用了这个方法。

public class BaseObservable implements Observable {
    private transient PropertyChangeRegistry mCallbacks;

    public BaseObservable() {
    }

    // 核心代码,反查下看拿引用
    @Override
    public void addOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {
        synchronized (this) {
            if (mCallbacks == null) {
                mCallbacks = new PropertyChangeRegistry();
            }
        }
        mCallbacks.add(callback);
    }

}
abstract class BaseObservableField extends BaseObservable {
    public BaseObservableField() {
    }

    public BaseObservableField(Observable... dependencies) {
        if (dependencies != null && dependencies.length != 0) {
            DependencyCallback callback = new DependencyCallback();

            for (int i = 0; i < dependencies.length; i++) {
                // 核心代码,是不是很熟悉,现在是不是有点感觉了为啥val nameF : ObservableField<String>能自动刷新数据呢。接着看
                dependencies[i].addOnPropertyChangedCallback(callback);
            }
        }
    }

    class DependencyCallback extends Observable.OnPropertyChangedCallback {
        @Override
        public void onPropertyChanged(Observable sender, int propertyId) {
            notifyChange();
        }
    }
}

   有点感觉了,为啥val nameF : ObservableField<String>能自动刷新数据更新Ui呢,我们知道livedata内部其实也是observer对象玩的,所以同理。我们就一个点去讲。ActivityMainBindingImpl是继承ViewDataBinding的,创建对象的时候就生成了WeakListListener对象

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

// 熟悉的味道,它集成了Observable.OnPropertyChangedCallback
private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
            implements ObservableReference<Observable> {
    final WeakListener<Observable> mListener;

    public WeakPropertyListener(
            ViewDataBinding binder,
            int localFieldId,
            ReferenceQueue<ViewDataBinding> referenceQueue
    ) {
        mListener = new WeakListener<Observable>(binder, localFieldId, this, referenceQueue);
    }

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

// ViewDataBinding.java
protected void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
    if (mInLiveDataRegisterObserver || mInStateFlowRegisterObserver) {
        return;
    }
    // 它来了他来了
    boolean result = onFieldChange(mLocalFieldId, object, fieldId);
    if (result) {
        requestRebind();  // 是不是又回来了
    }
}
    
    

   通过以上onChanged->handleFieldChange->ActivityMainBindingImpl.onFieldChange和requestRebind();。是不是熟悉的味道

// ActivityMainBindingImpl.java
@Override
protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
    switch (localFieldId) {
        case 0 :
            return onChangeMainVmNameF((androidx.databinding.ObservableField<java.lang.String>) object, fieldId);
        case 1 :
            return onChangeMainVmPwdF((androidx.databinding.ObservableField<java.lang.String>) object, fieldId);
    }
    return false;
}

private boolean onChangeMainVmNameF(androidx.databinding.ObservableField<java.lang.String> MainVmNameF, int fieldId) {
    if (fieldId == BR._all) {
        synchronized(this) {
                mDirtyFlags |= 0x1L;
        }
        return true;
    }
    return false;
}


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;
        }
        if (USE_CHOREOGRAPHER) {
            mChoreographer.postFrameCallback(mFrameCallback);
        } else {
            // 看到这个ui了吗?
            mUIThreadHandler.post(mRebindRunnable);
        }
    }
}

   是不是看到我们的ui线程了,其实不用说也知道是要更新ui了,再废话一波。

 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();
    }
};
ViewDataBinding.java
 public void executePendingBindings() {
    if (mContainingBinding == null) {
        executeBindingsInternal();
    } else {
        mContainingBinding.executePendingBindings();
    }
}
private void executeBindingsInternal() {
    if (mIsExecutingPendingBindings) {
        requestRebind();
        return;
    }
    if (!hasPendingBindings()) {
        return;
    }
    mIsExecutingPendingBindings = true;
    mRebindHalted = false;
    if (mRebindCallbacks != null) {
        mRebindCallbacks.notifyCallbacks(this, REBIND, null);

        if (mRebindHalted) {
            mRebindCallbacks.notifyCallbacks(this, HALTED, null);
        }
    }
    if (!mRebindHalted) {
        executeBindings(); //它又来了
        if (mRebindCallbacks != null) {
            mRebindCallbacks.notifyCallbacks(this, REBOUND, null);
        }
    }
    mIsExecutingPendingBindings = false;
}

   最后他又回到了ActivityMainBindingImpl. executeBindings();激动的心颤抖的手,

ActivityMainBindingImpl.java
@Override
protected void executeBindings() {
    long dirtyFlags = 0;
    synchronized(this) {
        dirtyFlags = mDirtyFlags;
        mDirtyFlags = 0;
    }
    com.wqg.wqgdatabdingandviewmodel.MainVm mainVm = mMainVm;
    java.lang.String mainVmNameFGet = null;
    androidx.databinding.ObservableField<java.lang.String> mainVmNameF = null;
    java.lang.String mainVmPwd = null;
    androidx.databinding.ObservableField<java.lang.String> mainVmPwdF = null;
    java.lang.String mainVmName = null;
    java.lang.String mainVmPwdFGet = null;

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

                if (mainVm != null) {
                    // read mainVm.nameF
                    mainVmNameF = mainVm.getNameF();
                }
                updateRegistration(0, mainVmNameF); // 这个就是observerField更新刷新ui


                if (mainVmNameF != null) {
                    // read mainVm.nameF.get()
                    mainVmNameFGet = mainVmNameF.get();
                }
        }
        if ((dirtyFlags & 0xcL) != 0) {

                if (mainVm != null) {
                    // read mainVm.pwd
                    mainVmPwd = mainVm.getPwd();
                    // read mainVm.name
                    mainVmName = mainVm.getName();
                }
        }
        if ((dirtyFlags & 0xeL) != 0) {

                if (mainVm != null) {
                    // read mainVm.pwdF
                    mainVmPwdF = mainVm.getPwdF();
                }
                updateRegistration(1, mainVmPwdF);


                if (mainVmPwdF != null) {
                    // read mainVm.pwdF.get()
                    mainVmPwdFGet = mainVmPwdF.get();
                }
        }
    }
    // batch finished
    if ((dirtyFlags & 0xcL) != 0) {
        androidx.databinding.adapters.TextViewBindingAdapter.setText(this.et1, mainVmName);
        androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv1, mainVmName);
        androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv2, mainVmPwd);
    }
    if ((dirtyFlags & 0x8L) != 0) {
        androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.et1, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, et1androidTextAttrChanged);
        androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.et2, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, et2androidTextAttrChanged);
    }
    if ((dirtyFlags & 0xdL) != 0) {
        androidx.databinding.adapters.TextViewBindingAdapter.setText(this.et2, mainVmNameFGet);
        androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv3, mainVmNameFGet);
    }
    if ((dirtyFlags & 0xeL) != 0) {
        androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tv4, mainVmPwdFGet);
    }
}

   上面我们看到了它会从vm的各个对象取值并更新给ui数据。其中updateRegistration(0, mainVmNameF); 是observerField对象更新数据了通知刷新ui,最后也是回到了requestRebind,下面说下

// ViewDataBinding.java
protected boolean updateRegistration(int localFieldId, Observable observable) {
    // CREATE_PROPERTY_LISTENER 是不是又回到之前说的了
    return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
}

  之前说过CREATE_PROPERTY_LISTENER对象,你可以把他当做它就是一个观察者,相当把observable封装到了CREATE_PROPERTY_LISTENER内部的WeakPropertyListener对应的target里面。甚至你可以理解他们是等价的,专门对属性进行监听,那是不是又回到之前WeakPropertyListener的讲解了。当属性发生变化的时候触发WeakPropertyListener.onPropertyChanged,之后就是前面说的代码了。

// 熟悉的味道,它集成了Observable.OnPropertyChangedCallback
private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
            implements ObservableReference<Observable> {
    final WeakListener<Observable> mListener;

    public WeakPropertyListener(
            ViewDataBinding binder,
            int localFieldId,
            ReferenceQueue<ViewDataBinding> referenceQueue
    ) {
        mListener = new WeakListener<Observable>(binder, localFieldId, this, referenceQueue);
    }

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

双向绑定咋实现的

  还是看刚刚上面代码,是不是又很熟悉了,它自己帮你添加监听回调了。这个比较简单就不过多介绍了,原理其实和上面差不多了

//监听
androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.et1, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, et1androidTextAttrChanged);


private androidx.databinding.InverseBindingListener et1androidTextAttrChanged = new androidx.databinding.InverseBindingListener() {
    @Override
    public void onChange() {
        java.lang.String callbackArg_0 = androidx.databinding.adapters.TextViewBindingAdapter.getTextString(et1);
        // localize variables for thread safety
        // mainVm
        com.wqg.wqgdatabdingandviewmodel.MainVm mainVm = mMainVm;
        // mainVm.name
        java.lang.String mainVmName = null;
        // mainVm != null
        boolean mainVmJavaLangObjectNull = false;

        mainVmJavaLangObjectNull = (mainVm) != (null);
        if (mainVmJavaLangObjectNull) {
            mainVm.setName(((java.lang.String) (callbackArg_0)));
        }
    }
};