Android databinding 原理浅析
通过一个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