欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android databinding 原理浅析

程序员文章站 2022-03-03 22:01:55
通过一个demo来分析下 databinding的原理通过此文章,希望能明白以下问题 :1.dataBinding 是如何将生成的 impl 实现类返回给我们的?2.当视图有变化时(通过 EditText 输入),为什么 跟其绑定的 bean 的属性会改变?3.当设置了 bean 类的某个属性时,为什么跟其绑定的视图会更新?demo如下:首先配置开启 databinding :android { ... dataBinding { enabl...

通过一个demo来分析下 databinding的原理

通过此文章,希望能明白以下问题 :

1.dataBinding 是如何将生成的 impl 实现类返回给我们的?

2.当视图有变化时(通过 EditText 输入),为什么 跟其绑定的 bean 的属性会改变?

3.当设置了 bean 类的某个属性时,为什么跟其绑定的视图会更新?

demo如下:

首先配置开启 databinding :

android {
     ...

    dataBinding {
        enabled true
    }
}

新建 SearchActivity.kt : 

package com.example.myapplication.databindingTes

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.example.myapplication.R
import com.example.myapplication.databinding.ActivitySearchBinding
import com.example.myapplication.databinding.ActivitySearchBindingImpl

class SearchActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var binding = DataBindingUtil.setContentView<ActivitySearchBinding>(
            this,
            R.layout.activity_search
        )

        var searchBean = SearchBean().apply {
            content.set("Google")
        }

        binding.searchBean = searchBean
    }
}

activity_search.xml : 

注意这里绑定用的是 @={} , @{}为单向绑定,@={}为双向绑定。

为某个模块启用视图绑定功能后,系统会为该模块中包含的每个 XML 布局文件生成一个绑定类。每个绑定类均包含对根视图以及具有 ID 的所有视图的引用。系统会通过以下方式生成绑定类的名称:将 XML 文件的名称转换为驼峰式大小写,并在末尾添加“Binding”一词,如我们的 xml 布局名称叫做 activity_search.xml ,生成的绑定类的名称就为 ActivitySearchBinding,所有生成的绑定类都是从 ViewDataBinding 类继承而来的,具体实现类是其名称后加 Impl ,如上面的就是 ActivitySearchBindingImpl。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="searchBean"
            type="com.example.myapplication.databindingTes.SearchBean" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".databindingTes.SearchActivity">
        <EditText
            android:id="@+id/et_search"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="@={searchBean.content}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
        <TextView
            android:id="@+id/tv_search"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="@={searchBean.content}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

    这里是给 EditText 和 TextView 都设置了和 searchBean.content 进行了双向绑定,当通过 EditText 编辑的时候 TextView 会同步改变。

SearchBean :

package com.example.myapplication.databindingTes

import androidx.databinding.ObservableField

class SearchBean() {
    var content: ObservableField<String> = ObservableField("搜索内容")
}

通过新建以上文件之后在 AndroidStudio 进行如下操作来生成文件:

Build -> Make Module 'app'

通过 make 操作,会生成一系列文件,如下图所示:

Android databinding 原理浅析

这里主要看图示箭头标注的三个类(注意一下包名,

有一个    androidx.databinding.DataBinderMapperImpl

com.xeample.myapplication.DataBinderMapperImpl)。

先看第一个问题:

1.dataBinding 是如何将生成的 impl 实现类返回给我们的?

在 SearchActivity.kt 中通过调用 DataBindingUtil.setContentView() 方法,

在 DataBindingUtil 中经过一系列的调用,

    public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity,
            int layoutId) {
        return setContentView(activity, layoutId, sDefaultComponent);
    }
    public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity,
            int layoutId, @Nullable DataBindingComponent bindingComponent) {
        ...
        ...
        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);
        }
    }

最终调用了 DataBindingUtil 的 bind() 方法,看一下此方法的实现,

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

发现这里是调用了 sMapper 的 getDataBinder 方法进行了返回,

先看下 sMapper 类 :

package androidx.databinding;

public class DataBinderMapperImpl extends MergedDataBinderMapper {
  DataBinderMapperImpl() {
    addMapper(new com.example.myapplication.DataBinderMapperImpl());
  }
}

注意这里是 androidx.databinding.DataBinderMapperImpl ,

androidx.databinding.DataBinderMapperImpl 继承了 androidx.databinding.MergedDataBinderMapper ,

在其构造方法里 调用了父类的 addMapper() 方法 ,添加了一个 com.example.myapplication.DataBinderMapperImpl 对象,

注意这里的 DataBinderMapperImpl 类名一样,包名不一样

我们之前看到 DataBindingUtil 的 bind() 方法 是调用了 sMapper.getDataBinder() 方法,也就是调用了 androidx.databinding.DataBinderMapperImpl 的 getDataBinder() 方法,然而, androidx.databinding.DataBinderMapperImpl 中并没有这个方法,但是其继承了 androidx.databinding.MergedDataBinderMapper 类,也就是说其是调用了父类的方法,我们去看下其父类 androidx.databinding.MergedDataBinderMapper 里的 getDataBinder() 的实现,

androidx.databinding.MergedDataBinderMapper.getDataBinder() :

package androidx.databinding;

...
...
@SuppressWarnings("unused")
public class MergedDataBinderMapper extends DataBinderMapper {
    ...
    ...
    private List<DataBinderMapper> mMappers = new CopyOnWriteArrayList<>();
    ...
    ...
    // 其子类构造方法通过此方法添加了 com.example.myapplication.DataBinderMapperImpl 对象
    @SuppressWarnings("WeakerAccess")
    public void addMapper(DataBinderMapper mapper) { 
        Class<? extends DataBinderMapper> mapperClass = mapper.getClass();
        if (mExistingMappers.add(mapperClass)) {
            mMappers.add(mapper);
            final List<DataBinderMapper> dependencies = mapper.collectDependencies();
            for(DataBinderMapper dependency : dependencies) {
                addMapper(dependency);
            }
        }
    }
    ...
    ...
    @Override
    public ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View view,
            int layoutId) {
         // 拿到上面添加过的 com.example.myapplication.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;
    }
    ...
    ...
}

这里可以看到是遍历了 mMappers,然后调用了 DataBinderMapper 的getDataBinder() ,那 mMappers 是什么时候添加了对象呢? 就是在其子类 androidx.databinding.DataBinderMapperImpl 的构造方法里,在其子类 androidx.databinding.DataBinderMapperImpl 的构造方法里,添加了一个 com.example.myapplication.DataBinderMapperImpl 对象,

也就是说 最终 androidx.databinding.MergedDataBinderMapper 的 getDataBinder() 方法 是调用了 com.example.myapplication.DataBinderMapperImpl 的 getDataBinder() 方法在 DataBindingUtil.bind() 里进行了返回。

看一下 com.example.myapplication.DataBinderMapperImpl.getDataBinder()

package com.example.myapplication;
...
...
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_ACTIVITYSEARCH: {
          if ("layout/activity_search_0".equals(tag)) {
            return new ActivitySearchBindingImpl(component, view); // 返回了 ViewDataBinding 的具体实现。
          }
          throw new IllegalArgumentException("The tag for activity_search is invalid. Received: " + tag);
        }
      }
    }
    return null;
  }
    ...
    ...
}

在这里返回了 ViewDataBinding 的具体实现。

现在梳理一下整个流程:

1. 在 SearchActivity.kt 中调用了 DataBindingUtil.setContentView() 方法。

2.在 DataBindingUtil 中经过一系列调用,最终调用了 DataBindingUtil.bind() 方法。

3.在 DataBindingUtil.bind() 中 调用了 sMapper.getDataBinder() 进行了返回。

4. sMapper 对象其实就是 androidx.databinding.DataBinderMapperImpl 对象,其在构造方法里添加了 com.example.myapplication.DataBinderMapperImpl 对象。

5.sMapper.getDataBinder() 其实是调用 androidx.databinding.DataBinderMapperImpl 的父类androidx.databinding.MergedDataBinderMapper 的 getDataBinder()

6.androidx.databinding.MergedDataBinderMapper 的 getDataBinder() 是调用的 androidx.databinding.DataBinderMapperImpl 的构造方法中添加的 com.example.myapplication.DataBinderMapperImpl 的 getDataBinder()。

7.SearchActivity.kt 中最终返回的是 com.example.myapplication.DataBinderMapperImpl.getDataBinder()

8. com.example.myapplication.DataBinderMapperImpl.getDataBinder() 返回了具体实现 ActivitySearchBindingImpl 对象。

2.当视图有变化时(通过 EditText 输入),为什么 跟其绑定的 bean 的属性会改变?

解答这个问题,需要先从 SearchActivity.kt 中说起,

SearchActivity 中 最后一句调用了 binding.searchBean = searchBean ,

先去看下这句话都做了些什么操作,

我们知道 模块中启用视图绑定之后,系统会为该模块中的每个 XML 布局文件生成一个绑定类,所有生成的绑定类都是从 ViewDataBinding 类继承而来的,类名称是基于布局文件的名称,它会转换为 Pascal 大小写形式并在末尾添加 Binding 后缀,并会生成一个后缀为 Impl 的具体实现类,如 demo 里生成的具体实现类是 ActivitySearchBindingImpl, 我们在 SearchActivity 中调用的 binding.searchBean = searchBean ,其实就是调用的 ActivitySearchBindingImpl 中的 setSearchBean(),然后在 setSearchBean() 里面调用了 ViewDataBinding.requestRebind(),在 ViewDataBinding.requestRebind() 中会判断 SDK 版本,不过最终都是执行了一个 Runnable 对象,如下图所示:

package androidx.databinding;

public abstract class ViewDataBinding extends BaseObservable {
    ...
    private static final boolean USE_CHOREOGRAPHER = SDK_INT >= 16;
    ...
    ...
    private final Runnable mRebindRunnable = new Runnable() {
        @Override
        public void run() {
            ...
            ...
            executePendingBindings();
        }
    };
    public void executePendingBindings() {
        if (mContainingBinding == null) {
            executeBindingsInternal();
        } else {
            mContainingBinding.executePendingBindings();
        }
    }    
    private void executeBindingsInternal() {
        ...
        ...
        if (!mRebindHalted) {
            executeBindings(); // 最后走到这里回调 ActivitySearchBindingImpl.executeBindings()。
            ...
        }
        mIsExecutingPendingBindings = false;
    }
    protected void requestRebind() {
        if (mContainingBinding != null) {
            mContainingBinding.requestRebind();
        } else {
            ...
            ...
            // 这里判断 SDK 版本号是否大于 16 , 最终都是执行了 mRebindRunnable。
            if (USE_CHOREOGRAPHER) {
                mChoreographer.postFrameCallback(mFrameCallback);
            } else {
                mUIThreadHandler.post(mRebindRunnable);
            }
        }
    }  
}

然后在 mRebindRunnable 里 经过 executePendingBindings() -> executeBindingsInternal() -> executeBindings() 最终调用了 executeBindings() 抽象方法 ,该抽象方法就是 ActivitySearchBindingImpl.executeBindings() ,所以就是说具体是在 ActivitySearchBindingImpl.executeBindings() 里面完成了视图和 bean 绑定的操作,

具体看下 ActivitySearchBindingImpl.java :

package com.example.myapplication.databinding;

@SuppressWarnings("unchecked")
public class ActivitySearchBindingImpl extends ActivitySearchBinding {
    ...
    ...
    // 生成一个 EditText 监听器。
    private androidx.databinding.InverseBindingListener etSearchandroidTextAttrChanged = new androidx.databinding.InverseBindingListener() {
        @Override
        public void onChange() {
            java.lang.String callbackArg_0 = androidx.databinding.adapters.TextViewBindingAdapter.getTextString(etSearch);
            boolean searchBeanJavaLangObjectNull = false;
            boolean searchBeanContentJavaLangObjectNull = false;
            java.lang.String searchBeanContentGet = null;
            com.example.myapplication.databindingTes.SearchBean searchBean = mSearchBean;
            androidx.databinding.ObservableField<java.lang.String> searchBeanContent = null;
            searchBeanJavaLangObjectNull = (searchBean) != (null);
            if (searchBeanJavaLangObjectNull) {
                searchBeanContent = searchBean.getContent();
                searchBeanContentJavaLangObjectNull = (searchBeanContent) != (null);
                if (searchBeanContentJavaLangObjectNull) {
                    // 当 EditText 内容改变时,给绑定的 bean 属性设置值。
                    searchBeanContent.set(((java.lang.String) (callbackArg_0)));
                }
            }
        }
    };
    // 跟上面EditText 一样,省略 TextView 的变化监听器
    private androidx.databinding.InverseBindingListener tvSearchandroidTextAttrChanged = new androidx.databinding.InverseBindingListener() {
        @Override
        public void onChange() {
            ...
            ...
        }
    };
    ...
    ...
    // 在 activity 中设置会调用此方法。
    public void setSearchBean(@Nullable com.example.myapplication.databindingTes.SearchBean SearchBean) {
        this.mSearchBean = SearchBean;
        synchronized (this) {
            mDirtyFlags |= 0x2L;
        }
        notifyPropertyChanged(BR.searchBean);
        super.requestRebind(); // 调用父类实现。
    }
    ...
    ...
    // 最终回调此方法,在此方法中完成绑定。
    @Override
    protected void executeBindings() {
        long dirtyFlags = 0;
        ...
        if ((dirtyFlags & 0x7L) != 0) {
            if (searchBean != null) {               
                searchBeanContent = searchBean.getContent();
            }
            updateRegistration(0, searchBeanContent); // 注册 bean 属性变化监听。
            if (searchBeanContent != null) {
                searchBeanContentGet = searchBeanContent.get();
            }
        }
        ...
        if ((dirtyFlags & 0x7L) != 0) { // 在此处设置数据。
            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.etSearch, searchBeanContentGet);
            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tvSearch, searchBeanContentGet);
        }
        if ((dirtyFlags & 0x4L) != 0) { // 在此处视图变化设置监听器。
            androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.etSearch,
                    (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged) null,
                    (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged) null,
                    (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged) null,
                    etSearchandroidTextAttrChanged); // 给 EditText 设置监听器。
            androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.tvSearch,
                    (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged) null,
                    (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged) null,
                    (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged) null,
                    tvSearchandroidTextAttrChanged); // 给 TextView 设置监听器。
        }
    }
    ...
}

总结一下:

    当我们在 activity_search.xml 中声明了数据对象,数据绑定库会自动生成将布局中的视图与数据对象绑定所需的类 ActivitySearchBindingImpl.java,当我们在 SearchActivity.kt 中设置数据对象( binding.searchBean = searchBean )的时候,会经过一系列的方法调用 :

ActivitySearchBindingImpl.setSearchBean() -> ViewDataBinding.requestRebind() -> ViewDataBinding.executePendingBindings() -> ViewDataBinding.executeBindingsInternal() -> ActivitySearchBindingImpl.executeBindings()

最终在 ActivitySearchBindingImpl.executeBindings() 中完成绑定操作,具体操作就是 为给设置了数据对象属性绑定的视图(EditText 和 TextView ) 设置监听器,在视图据发生改变的时候进行数据( searchBean.content )的设置。

3.当设置了 bean 类的某个属性时,为什么跟其绑定的视图会更新?

通过上面我们知道,当我们在 SearchActivity.kt 中执行 binding.searchBean = searchBean 时,经过一系列调用,最后会调用 ActivitySearchBindingImpl.executeBindings(),在此方法中有一个刚才没提到的方法 updateRegistration(),这个方法就是设置数据对象改变时的监听,传入了需要监听的属性对象 searchBeanContent,如下图所示:

package com.example.myapplication.databinding;
public class ActivitySearchBindingImpl extends ActivitySearchBinding {
    ...
    ...
    // 最终回调此方法,在此方法中完成绑定。
    @Override
    protected void executeBindings() {
        ...
        ...
        androidx.databinding.ObservableField<java.lang.String> searchBeanContent = null;
        if ((dirtyFlags & 0x7L) != 0) {
            if (searchBean != null) {               
                searchBeanContent = searchBean.getContent();
            }
            // 注册 bean 属性变化监听,此处传入了需要监听的属性对象 searchBeanContent。
            updateRegistration(0, searchBeanContent);
            if (searchBeanContent != null) {
                searchBeanContentGet = searchBeanContent.get();
            }
        }
        ...
        ...
}

跟着 updateRegistration() 方法进去,发现调用的是 ViewDataBinding 的 updateRegistration() 方法,看一下这个方法:

     protected boolean updateRegistration(int localFieldId, Observable observable) {
        // CREATE_PROPERTY_LISTENER 是上面的 WeakPropertyListener 对象。
        return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
    }

这里有一个 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();
        }
    };  

通过上面代码可以看出,CREATE_PROPERTY_LISTENER 是通过创建一个 WeakPropertyListener 对象,然后调用其 getListener() 方法进行了返回,我们继续去看下 WeakPropertyListener 这个类的实现,

private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
            implements ObservableReference<Observable> {
        final WeakListener<Observable> mListener;
        public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
            mListener = new WeakListener<Observable>(binder, localFieldId, this); // 和 weakListener 互相引用
        }
        ...
    }

这里可以看到,

1.WeakPropertyListener 对象实现了 ObservableReference<Observable> 

2.在 WeakPropertyListener 构造方法里新建了一个 WeakListener<Observable>,并传入了 this 来和 WeakListener<Observable> 进行互相引用,即  WeakPropertyListener 和 WeakListener 互相持有对方。

WeakPropertyListener 看完了,我们继续接着刚才的流程往下看 updateRegistration() 方法,

    private boolean updateRegistration(int localFieldId, Object observable,
            CreateWeakListener listenerCreator) {
        ...
        WeakListener listener = mLocalFieldObservers[localFieldId];
        if (listener == null) {
            registerTo(localFieldId, observable, listenerCreator); // 这里调用了下面的 registerTo() 方法
            return true;
        }
       ...
    }

    protected void registerTo(int localFieldId, Object observable,
            CreateWeakListener listenerCreator) {
        ...
        WeakListener listener = mLocalFieldObservers[localFieldId];
        ...
        // listener 是 WeakListener 对象。
        // observable 是刚才的 searchBeanContent 对象。
        listener.setTarget(observable); // 最终调用到此。
    }

通过上图可以看到,在 updateRegistration() 中调用了 registerTo() 方法,

在 registerTo() 中,最终执行 listener.setTarget(observable) 结束,

其中 listener 是通过常量 CREATE_PROPERTY_LISTENER 创建的 WeakListener 对象,其持有一个 WeakPropertyListener 对象,observable 是刚才的 searchBeanContent 对象,

我们去看下 WeakListener 的 setTarget() 是怎么实现的

private static class WeakListener<T> extends WeakReference<ViewDataBinding> {
        private final ObservableReference<T> mObservable; // WeakPropertyListener 对象。
        protected final int mLocalFieldId;
        private T mTarget;
        public WeakListener(ViewDataBinding binder, int localFieldId,ObservableReference<T> observable) {
            super(binder, sReferenceQueue);
            mLocalFieldId = localFieldId;
            mObservable = observable; // 跟 WeakPropertyListener 双向绑定。
        }
        ...
        public void setTarget(T object) {
            unregister();
            mTarget = object;
            if (mTarget != null) {
                // mObservable 是 WeakPropertyListener 对象。
                // mTarget 是 searchBeanContent 对象。
                mObservable.addListener(mTarget); // 执行了此行。
            }
        }
        ...
    }

发现执行了 mObservable.addListener(mTarget);

其中 mObservable 就是双向持有的 WeakPropertyListener 对象,

即调用了 WeakPropertyListener 的 addListener() 方法,参数是我们之前传过来的 searchBeanContent 对象,

然后我们跟进去看下 WeakPropertyListener 的 addListener() 方法

private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
            implements ObservableReference<Observable> {
        final WeakListener<Observable> mListener;
        public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
            mListener = new WeakListener<Observable>(binder, localFieldId, this); // 这里和 WeakListener 双向绑定
        }
        ...
        @Override
        public void addListener(Observable target) { 
            target.addOnPropertyChangedCallback(this); // 添加属性变化监听器
        }
        ...
        @Override
        public void onPropertyChanged(Observable sender, int propertyId) { // 属性变化时回调。
            ViewDataBinding binder = mListener.getBinder();
            ...
            binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId); // 当属性有变化时,调用了此方法。
        }
    }

从上图可以看到,addListener() 方法就是给 target 添加了一个属性变化回调监听器,target 对象是从之前传过来的 searchBeanContent 对象,传入的值是 this , 也就是自身,由于 WeakPropertyListener 本身实现了 ObservableReference<Observable> , 所以 当 target 属性发生变化的时候,会回调 WeakPropertyListener 的 onPropertyChanged() 方法。onPropertyChanged() 方法最后调用了 ViewDataBinding 的 handleFieldChange() 方法,先去看下这个方法的实现,这个方法是在 ViewDataBinding 中实现的:

ViewDataBinding.java : 

    private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
        ...
        boolean result = onFieldChange(mLocalFieldId, object, fieldId);
        if (result) {
            requestRebind();
        }
    }

可以看到最后还是调用了 requestRebind() 方法,通过 问题2 我们可以知道,当我们调用 ActivitySearchBindingImpl 的 setSearchBean() 方法的时候,调用的就是 ViewDataBinding 的 requestRebind() 方法,requestRebind() 是将数据和视图绑定并设置视图监听器的方法,所以这里就是又设置了一次视图,到此,完成数据变更,视图更新的操作。

梳理一下过程:

    1.在 ActivitySearchBindingImpl 的 executeBindings() 方法中,调用 updateRegistration(0, searchBeanContent);

    2.然后调用了 ViewDataBinding 的 updateRegistration(int localFieldId, Object observable,CreateWeakListener listenerCreator) 方法中,传入了 CREATE_PROPERTY_LISTENER 对象,这个对象是一个和 WeakPropertyListener 双向绑定的 WeakListener 对象。

    3.之后调用 ViewDataBinding 的 registerTo(localFieldId, observable, listenerCreator); 在 registerTo() 中调用了 WeakListener 的 setTarget() 方法。

    4.在 WeakListener 的 setTarget() 方法中,调用了与其双向绑定的 WeakPropertyListener 的 addListener() 方法。

    5.在 WeakPropertyListener 的 addListener() 方法中给 searchBeanContent 对象 添加了属性变化监听器,值就是其本身(其自身实现了 ObservableReference<Observable>),这样就实现了 当 searchBeanContent 对象 发生变化时会回调其 onPropertyChanged() 方法。

    6.当 searchBeanContent 对象 发生变化时,回调 WeakPropertyListener 的 onPropertyChanged() 方法,在 onPropertyChanged() 中 通过与其双向绑定的 WeakListener 的 getBinder() 方法,拿到 ViewDataBinding 对象,然后调用 ViewDataBinding 对象的 handleFieldChange() 方法。

    7.ViewDataBinding 对象的 handleFieldChange() 方法 最终调用了 requestRebind() 方法, requestRebind() 将视图和数据重新进行设置。

 

 

 

 

 

本文地址:https://blog.csdn.net/qq_31872881/article/details/108083972