当前位置: 移动技术网 > 移动技术>移动开发>Android > Android databinding 原理浅析

Android databinding 原理浅析

2020年08月01日  | 移动技术网移动技术  | 我要评论
通过一个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 操作,会生成一系列文件,如下图所示:

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

有一个    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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网