1、基础使用
无须添加依赖,在模块 build.gradle 的 android 节点下开启 dataBinding:
android {
...
dataBinding {
enabled = true
}
}
让 JavaBean 继承 BaseObservable,用 @Bindable 注解修饰需要绑定的属性的 getter 方法,并在该属性的 setter 方法中调用 notifyPropertyChanged(BR.propertyName) 告诉系统需要更新哪一个属性:
public class User extends BaseObservable {
public String name;
public User(String name) {
this.name = name;
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
}
修改布局文件,使用 <layout> 标签作为根标签,通过 <data> 配置数据源,布局组件中的相关信息通过数据源获取:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="user"
type="com.demo.databinding.User" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}" />
</LinearLayout>
</layout>
最后在 Activity 中使用 DataBindingUtil 设置布局,并通过 binding 对象对属性进行修改:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
User user = new User("Test");
binding.setUser(user);
}
}
更多使用方法与案例可参考官方文档数据绑定库。
2、布局解析
2.1 布局分离
DataBindingUtil 在加载布局文件时会将其分离成两个文件,以上例中的 MainActivity 为例,使用的布局文件为 activity_main.xml,那么在 build 目录下会为其生成两个相关文件:
- build/intermediates/data_binding_layout_info_type_merge/activity_main-layout.xml
- build/intermediates/incremental/mergeDebugResources/stripped.dir/layout/activity_main.xml
其中新生成的 activity_main.xml 与原本的 activity_main.xml 非常相似,区别在于前者在布局内的所有控件中添加了 android:tag 属性:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:tag="layout/activity_main_0">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tag="binding_1" />
</LinearLayout>
而 activity_main-layout.xml 内存放的是 activity_main.xml 的各种信息,其中 Target 标签存放着各个控件的信息,包括该控件的类型以及 android:tag 的属性值:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Layout directory="layout" filePath="databinding\src\main\res\layout\activity_main.xml"
isBindingData="true" isMerge="false" layout="activity_main"
modulePackage="com.demo.databinding" rootNodeType="android.widget.LinearLayout">
<Variables name="user" declared="true" type="com.demo.databinding.User">
<location endLine="6" endOffset="46" startLine="4" startOffset="8" />
</Variables>
<Targets>
<!-- Target 标签对应原本 layout 文件中的各个控件 -->
<Target tag="layout/activity_main_0" view="LinearLayout">
<Expressions />
<location endLine="19" endOffset="18" startLine="9" startOffset="4" />
</Target>
<Target tag="binding_1" view="TextView">
<Expressions>
<Expression attribute="android:text" text="user.name">
<Location endLine="17" endOffset="38" startLine="17" startOffset="12" />
<TwoWay>false</TwoWay>
<ValueLocation endLine="17" endOffset="36" startLine="17" startOffset="28" />
</Expression>
</Expressions>
<location endLine="17" endOffset="41" startLine="14" startOffset="8" />
</Target>
</Targets>
</Layout>
Expression 标签中的属性 android:text 会被赋值为 user.name。
2.2 将布局控件转换成控件对象
回过头我们来看 Java 代码,DataBindingUtil 的 setContentView() 会把 android.R.id.content 内的所有控件都实例化并绑定到 ActivityMainBindingImpl 内对应的对象上,这样就可以使用类似 binding.textView 这样的语法直接获取控件对象了。
public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity,
int layoutId, @Nullable DataBindingComponent bindingComponent) {
// 原本 Activity 的 setContentView() 还是要做的
activity.setContentView(layoutId);
// 拿到 DecorView 中的 contentView,即 android.R.id.content 表示的部分
View decorView = activity.getWindow().getDecorView();
ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content);
// 对 contentView 中的所有 View 进行绑定
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) {
// contentView 中只有一个子 view
final View childView = parent.getChildAt(endChildren - 1);
return bind(component, childView, layoutId);
} else {
// contentView 中有多个子 view
final View[] children = new View[childrenAdded];
for (int i = 0; i < childrenAdded; i++) {
children[i] = parent.getChildAt(i + startChildren);
}
return bind(component, children, layoutId);
}
}
由于 Activity.setContentView() 已经把 layoutId 对应的布局资源解析并创建了控件对象,因此可以直接通过 findViewById() 获取到 android.R.id.content 对应的 contentView 对象,并通过 bind() 将 contentView 的子控件与 ActivityMainBindingImpl 内声明的控件对象进行绑定。
bind() 将具体的绑定工作交给 sMapper:
private static DataBinderMapper sMapper = new DataBinderMapperImpl();
static <T extends ViewDataBinding> T bind(DataBindingComponent bindingComponent, View root,
int layoutId) {
return (T) sMapper.getDataBinder(bindingComponent, root, layoutId);
}
static <T extends ViewDataBinding> T bind(DataBindingComponent bindingComponent, View[] roots,
int layoutId) {
return (T) sMapper.getDataBinder(bindingComponent, roots, layoutId);
}
而 bind() 又会调用 DataBinderMapperImpl() 的 getDataBinder():
package androidx.databinding;
public class DataBinderMapperImpl extends MergedDataBinderMapper {
DataBinderMapperImpl() {
// 注意这里添加进去的是不同包下的同名类
addMapper(new com.demo.databinding.DataBinderMapperImpl());
}
}
-----------------------------------------------------------------------
public class MergedDataBinderMapper extends DataBinderMapper {
private Set<Class<? extends DataBinderMapper>> mExistingMappers = new HashSet<>();
private List<DataBinderMapper> mMappers = new CopyOnWriteArrayList<>();
// 将 mapper 以及 mapper 依赖的对象全部添加进 mExistingMappers 和 mMappers
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) {
// 遍历 mMappers 通过 DataBinderMapper 的 getDataBinder() 获取最终结果
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 中添加的就是 com.demo.databinding.DataBinderMapperImpl,所以我们去看这个类的 getDataBinder():
@Override
public ViewDataBinding getDataBinder(DataBindingComponent component, View view, int layoutId) {
// 容量为 1 的 SparseIntArray
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: {
// 这个 id 是 build 目录下生成的 activity_main.xml 中根节点的 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 {
...
// 布局文件中的所有控件
// views
@NonNull
private final android.widget.LinearLayout mboundView0;
@NonNull
private final android.widget.TextView mboundView1;
public ActivityMainBindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
// mapBindings() 会生成控件对象组成的数组
this(bindingComponent, root, mapBindings(bindingComponent, root, 2, sIncludes, sViewsWithIds));
}
private ActivityMainBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
super(bindingComponent, root, 1);
// 从 bindings 中取出控件对象赋值给对应的成员
this.mboundView0 = (android.widget.LinearLayout) bindings[0];
this.mboundView0.setTag(null);
this.mboundView1 = (android.widget.TextView) bindings[1];
this.mboundView1.setTag(null);
setRootTag(root);
// listeners
invalidateAll();
}
}
先通过 mapBindings() 将表示控件的 View 对象存到 bindings 数组中合适的位置上:
// numBindings 是指布局文件中控件的个数,activity_main 内有 LinearLayout 和 TextView,
// 所以在调用本方法时给 numBindings 传的是 2,表示布局中有两个控件节点
protected static Object[] mapBindings(DataBindingComponent bindingComponent, View root,
int numBindings, IncludedLayouts includes, SparseIntArray viewsWithIds) {
Object[] bindings = new Object[numBindings];
// xml 解析过程,最终把解析到的 View 添加到 bindings 数组中
mapBindings(bindingComponent, root, bindings, includes, viewsWithIds, true);
return bindings;
}
// 将 view 填充到 bindings 数组的合适的位置上
private static void mapBindings(DataBindingComponent bindingComponent, View view,
Object[] bindings, IncludedLayouts includes, SparseIntArray viewsWithIds,
boolean isRoot) {
final int indexInIncludes;
// 获取 View 的标签:(ViewDataBinding)view.getTag(R.id.dataBinding)
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)) {
// 解析 tag 得出它应该保存在 bindings 中的哪个 index 中
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)) {
// 处理 tag 是以 binding_ 开头的控件
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;
}
}
}
...
}
拿到 bindings 数组之后,在 ActivityMainBindingImpl 的构造方法中,将 bindings 数组中的 View 赋值给对应的控件对象,这样就完成了由布局文件到对象的绑定,可以直接通过 ActivityMainBinding 获取控件了。
3、数据绑定解析
关注数据的变化是如何体现到 UI 上的。
在 MainActivity 中修改 User 的方式有两种:
binding.setUser(user);
binding.setVariable(BR.user, user);
实际上第二种方式也会调用 setUser(),因此我们从 ActivityMainBindingImpl.setVariable() 看起:
@Override
public boolean setVariable(int variableId, @Nullable Object variable) {
boolean variableSet = true;
if (BR.user == variableId) {
setUser((com.demo.databinding.User) variable);
}
// 如果还有其他类实现了 BaseObservable 并且绑定了属性,会有类似如下的代码:
/*else if (BR.student == variableId) {
setStudent((com.demo.databinding.Student) variable);
}*/
else {
variableSet = false;
}
return variableSet;
}
BR 是 APT 生成的文件,保存着实现了 BaseObservable 的类及其内部绑定的属性:
public class BR {
// 表示所有属性
public static final int _all = 0;
// User 中的属性
public static final int name = 1;
// User 本身实现了 BaseObservable
public static final int user = 2;
// 如果还有其他类实现了 BaseObservable,那么其被绑定的属性会接着序号3、4、5...向下排
}
User 对象发生变化时会执行 setUser():
public void setUser(@Nullable com.demo.databinding.User User) {
// 1.更新注册信息
updateRegistration(0, User);
this.mUser = User;
synchronized (this) {
mDirtyFlags |= 0x1L;
}
// 2.通知属性变化
notifyPropertyChanged(BR.user);
// 3.重新绑定数据
super.requestRebind();
}
下面来看这三个过程。
3.1 更新注册信息
ViewDataBinding.updateRegistration() 更新的是要监听的 BaseObservable 的子类对象,在当前流程中就是 User 对象。在看 updateRegistration() 的内容之前,需要先了解一下 ViewDataBinding 中的重要成员。
WeakListener
ViewDataBinding 内维护着一个 WeakListener 类型的数组 mLocalFieldObservers:
private WeakListener[] mLocalFieldObservers;
“更新注册”其实就是更新这个数组中的内容,它的元素 WeakListener 看似是一个监听器:
private static class WeakListener<T> extends WeakReference<ViewDataBinding> {
// mObservable 实际上是一个 WeakPropertyListener
private final ObservableReference<T> mObservable;
// 属性 ID,对应 BR 文件中的常量值
protected final int mLocalFieldId;
// 被观察者,数据发生变化的对象
private T mTarget;
public WeakListener(ViewDataBinding binder, int localFieldId,
ObservableReference<T> observable) {
super(binder, sReferenceQueue);
mLocalFieldId = localFieldId;
mObservable = observable;
}
...
public void setTarget(T object) {
unregister();
mTarget = object;
if (mTarget != null) {
// 将被观察者添加到 ObservableReference 接口实例中
mObservable.addListener(mTarget);
}
}
@Nullable
protected ViewDataBinding getBinder() {
// WeakListener 首先是一个 WeakReference<ViewDataBinding>,
// 通过 get() 可以得到 ViewDataBinding 对象
ViewDataBinding binder = get();
if (binder == null) {
unregister(); // The binder is dead
}
return binder;
}
}
WeakListener 的三个成员:
T mTarget
:被监听的数据,支持 4 中形式,分别是 Property、List、Map 和 LiveData,要求分别继承或实现 Observable、ObservableList、ObservableMap 和 LiveDataObservableReference<T> mObservable
:ObservableReference 有 4 个实现类,属性监听器 WeakPropertyListener、列表监听器 WeakListListener、Map 监听器 WeakMapListener 和 LiveData 监听器 LiveDataListenerint mLocalFieldId
:属性对应在 BR 文件内的 Id
ObservableReference
此外还需了解一下 ObservableReference 这个接口:
private interface ObservableReference<T> {
// 获取实现类内持有的 WeakListener
WeakListener<T> getListener();
// 给 target 设置监听器
void addListener(T target);
// 移除 target 上的监听器
void removeListener(T target);
// 设置生命周期宿主
void setLifecycleOwner(LifecycleOwner lifecycleOwner);
}
该接口有四个实现类,分别为 WeakPropertyListener、WeakListListener、WeakMapListener 和 LiveDataListener,看名字能猜出,它们分别是监听属性、List、Map 和 LiveData 变化的监听器。对应这四个监听器,有四个 CreateWeakListener 类型的常量,分别创建包含这四个监听器对象的 WeakListener:
private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
@Override
public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();
}
};
private static final CreateWeakListener CREATE_LIST_LISTENER = new CreateWeakListener() {
@Override
public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
return new WeakListListener(viewDataBinding, localFieldId).getListener();
}
};
private static final CreateWeakListener CREATE_MAP_LISTENER = new CreateWeakListener() {
@Override
public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
return new WeakMapListener(viewDataBinding, localFieldId).getListener();
}
};
private static final CreateWeakListener CREATE_LIVE_DATA_LISTENER = new CreateWeakListener() {
@Override
public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
return new LiveDataListener(viewDataBinding, localFieldId).getListener();
}
};
实际上 mLocalFieldObservers 数组内保存的 WeakListener 对象就来自于上述 CreateWeakListener 的 create()。
由于我们现在在看属性变化的过程,那么自然就要关注 CREATE_PROPERTY_LISTENER 创建的 WeakPropertyListener 了:
private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
implements ObservableReference<Observable> {
// 提供 ViewDataBinding 和 Observable 对象,以及属性 ID 信息
final WeakListener<Observable> mListener;
public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
mListener = new WeakListener<Observable>(binder, localFieldId, this);
}
// ObservableReference 接口方法
@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) {
}
// Observable.OnPropertyChangedCallback 在属性变化时回调该方法
@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?
}
// 处理属性变化的任务交给 ViewDataBinding
binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
}
}
当属性发生变化的时候,会回调 Observable.OnPropertyChangedCallback 的 onPropertyChanged(),这时候将 mListener 中的信息交给 ViewDataBinding,由其处理属性变化的相关事宜。
注册过程
这下我们再来看 updateRegistration() 的具体内容:
protected boolean updateRegistration(int localFieldId, Observable observable) {
return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
}
/**
* localFieldId 是被注册的属性的 ID,在 BR 文件中
* observable 是被观察者,例如实现了 BaseObservable 的 User 类
* CREATE_PROPERTY_LISTENER 是属性发生变化时用到的监听器的创建者
* setUser() 内调用本方法时传的是 (0,User),表示更新 User 类内的所有属性
*/
private boolean updateRegistration(int localFieldId, Object observable,
CreateWeakListener listenerCreator) {
if (observable == null) {
return unregisterFrom(localFieldId);
}
// mLocalFieldObservers 在 ViewDataBinding 的构造方法中初始化,在 registerTo() 中被赋值
WeakListener listener = mLocalFieldObservers[localFieldId];
// listener 为空说明还没有为 mLocalFieldObservers[localFieldId] 位置上
// 创建监听器对象,通过 registerTo() 为其创建
if (listener == null) {
registerTo(localFieldId, observable, listenerCreator);
return true;
}
// 监听器的目标就是当前传入的 observable 对象,就不需要更新注册信息
if (listener.getTarget() == observable) {
return false;//nothing to do, same object
}
// 走到这说明注册信息发生了改变,需要先解除原本注册的信息,再重新注册新信息
unregisterFrom(localFieldId);
registerTo(localFieldId, observable, listenerCreator);
return true;
}
registerTo() 会在 mLocalFieldObservers[localFieldId] 不存在的时候通过 CreateWeakListener 创建一个 WeakListener 保存到该位置上:
protected void registerTo(int localFieldId, Object observable,
CreateWeakListener listenerCreator) {
if (observable == null) {
return;
}
WeakListener listener = mLocalFieldObservers[localFieldId];
if (listener == null) {
// 为 localFieldId 创建 WeakListener
listener = listenerCreator.create(this, localFieldId);
// 将监听器保存到 mLocalFieldObservers 数组 localFieldId 的位置上
mLocalFieldObservers[localFieldId] = listener;
if (mLifecycleOwner != null) {
listener.setLifecycleOwner(mLifecycleOwner);
}
}
// 设置监听器目标,将被观察者绑定到监听器上
listener.setTarget(observable);
}
这样看下来,updateRegistration() 更新的其实是 WeakListener 的监听目标 mTarget,在例子中就是 User 对象。
总结一下就是 ViewDataBinding 内的 mLocalFieldObservers 数组会按照 BR 文件中的属性 ID 存储对应的 WeakListener 对象,当属性发生变化时,会通知到 WeakListener 中持有的 WeakPropertyListener 监听器,回调 onPropertyChanged() 将处置事宜交还给 ViewDataBinding。
3.2 属性变化处理
通知属性变化
下面来分析,属性发生变化时,发出通知的流程。这个要去看 User 类继承的 BaseObservable:
public class BaseObservable implements Observable {
private transient PropertyChangeRegistry mCallbacks;
public void notifyPropertyChanged(int fieldId) {
synchronized (this) {
if (mCallbacks == null) {
return;
}
}
// 调用 PropertyChangeRegistry 父类 CallbackRegistry 的 notifyCallbacks()
mCallbacks.notifyCallbacks(this, fieldId, null);
}
}
CallbackRegistry 内的调用链长了一些,notifyCallbacks() -> notifyRecurse() -> notifyRemainder() -> notifyFirst64() -> notifyCallbacks(),我们只贴最后一个方法的代码:
private void notifyCallbacks(T sender, int arg, A arg2, final int startIndex,
final int endIndex, final long bits) {
long bitMask = 1;
for (int i = startIndex; i < endIndex; i++) {
if ((bits & bitMask) == 0) {
// 回调 PropertyChangeRegistry 的 NOTIFIER_CALLBACK 中的 onNotifyCallback()
mNotifier.onNotifyCallback(mCallbacks.get(i), sender, arg, arg2);
}
bitMask <<= 1;
}
}
for 循环内会回调 PropertyChangeRegistry 常量 NOTIFIER_CALLBACK 的 onNotifyCallback():
private static final CallbackRegistry.NotifierCallback<Observable.OnPropertyChangedCallback, Observable, Void> NOTIFIER_CALLBACK = new CallbackRegistry.NotifierCallback<Observable.OnPropertyChangedCallback, Observable, Void>() {
@Override
public void onNotifyCallback(Observable.OnPropertyChangedCallback callback, Observable sender,
int arg, Void notUsed) {
callback.onPropertyChanged(sender, arg);
}
};
看 callback 的类型,眼熟吗?正是【3.1 更新注册信息】ObservableReference 中介绍的 WeakPropertyListener,当回调其 onPropertyChanged() 时,会把处理属性变化的任务交给 ViewDataBinding。
处理属性变化
接着上一步来到 ViewDataBinding 的 handleFieldChange():
private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
if (mInLiveDataRegisterObserver) {
// We're in LiveData registration, which always results in a field change
// that we can ignore. The value will be read immediately after anyway, so
// there is no need to be dirty.
return;
}
boolean result = onFieldChange(mLocalFieldId, object, fieldId);
if (result) {
requestRebind();
}
}
onFieldChange() 执行的是具体实现类中的同名方法,在我们这个例子中就是 ActivityMainBindingImpl:
// setUser(BR.user) 参数 BR.user 是这里的 fieldId
@Override
protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
switch (localFieldId) {
case 0:
return onChangeUser((com.demo.databinding.User) object, fieldId);
}
return false;
}
private boolean onChangeUser(com.demo.databinding.User User, int fieldId) {
if (fieldId == BR._all) {
synchronized (this) {
mDirtyFlags |= 0x1L;
}
return true;
} else if (fieldId == BR.name) {
synchronized (this) {
mDirtyFlags |= 0x2L;
}
return true;
}
return false;
}
如果发生变更的属性满足上述条件会返回 true,进而执行 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 做的是 SDK 版本兼容操作,SDK >=16 会走 if,实际上最终也是去执行 else 中的 post()
if (USE_CHOREOGRAPHER) {
mChoreographer.postFrameCallback(mFrameCallback);
} else {
mUIThreadHandler.post(mRebindRunnable);
}
}
}
执行 mRebindRunnable 任务:
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();
}
};
经过调用链 executePendingBindings() -> executeBindingsInternal() -> executeBindings():
// ActivityMainBindingImpl
@Override
protected void executeBindings() {
long dirtyFlags = 0;
synchronized (this) {
// mDirtyFlags 决定对哪一个属性进行处理
dirtyFlags = mDirtyFlags;
mDirtyFlags = 0;
}
java.lang.String userName = null;
com.demo.databinding.User user = mUser;
if ((dirtyFlags & 0x7L) != 0) {
if (user != null) {
// 获取 User 的 name 属性值
userName = user.getName();
}
}
// batch finished
if ((dirtyFlags & 0x7L) != 0) {
// 将 userName 设置给相应位置的 TextView
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView1, userName);
}
}
最终会通过 TextViewBindingAdapter 的 setText() 将变化后的值在 UI 上进行修改:
@BindingAdapter("android:text")
public static void setText(TextView view, CharSequence text) {
final CharSequence oldText = view.getText();
if (text == oldText || (text == null && oldText.length() == 0)) {
return;
}
if (text instanceof Spanned) {
if (text.equals(oldText)) {
return; // No change in the spans, so don't set anything.
}
} else if (!haveContentsChanged(text, oldText)) {
return; // No content changes, so don't set anything.
}
// 目标
view.setText(text);
}
3.3 重新绑定
最后看 setUser() 的第三步,super.requestRebind() 实际上调用的就是 ViewDataBinding 中的方法,该方法在【3.2 属性变化处理 -> 处理属性变化】一节中已经说明,这里就不再赘述。