项目有三个moduel:app、business,其中app为空moduel,里面没有具体代码,business主要放业务相关的代码,又有两个目录home和baseui。在app moduel和baseui包和home包的build目录下生成的代码目录如下:
可以看到在四个目录中分别都生成了一个DataBinderMapperImpl类。这里说明两点:
以DataBindingUtil的inflate()方法为切入点来分析绑定过程。
public static T inflate(
@NonNull LayoutInflater inflater, int layoutId, @Nullable ViewGroup parent,
boolean attachToParent, @Nullable DataBindingComponent bindingComponent) {
final boolean useChildren = parent != null && attachToParent;
final int startChildren = useChildren ? parent.getChildCount() : 0;
final View view = inflater.inflate(layoutId, parent, attachToParent);
if (useChildren) {
return bindToAddedViews(bindingComponent, parent, startChildren, layoutId);
} else {
return bind(bindingComponent, view, layoutId);
}
}
在Fragment的onCreateView()方法中初始化布局时往往给attachToParent参数传值为false,因此会执行bind()方法,bindingComponent默认情况下为null。
//DataBindingUtil.kt
private static DataBinderMapper sMapper = new DataBinderMapperImpl();
static T bind(DataBindingComponent bindingComponent, View root,
int layoutId) {
return (T) sMapper.getDataBinder(bindingComponent, root, layoutId);
}
这里要注意sMapper到底是上面生成的三个DataBinderMapperImpl中的哪一个,DataBindingUtil的包名为androidx.databinding,注意到app moduel下的第一个DataBinderMapperImpl的包名也是androidx.databinding,因此就是这个类了:
package androidx.databinding;
public class DataBinderMapperImpl extends MergedDataBinderMapper {
DataBinderMapperImpl() {
addMapper(new com.yy.oms.logistics.DataBinderMapperImpl());
}
}
该类的代码十分简单,起作用是做为查找其他节点的入口,我将其称做“根DataBinderMapperImpl”,在构造函数中调用了父类MergedDataBinderMapper的addMapper()方法:
//MergedDataBinderMapper.java
// we keep set of existing classes so that addMapper can avoid re-adding same class.
// usually not necessary as list lookup might be sufficient but if the project has 100+
// modules, it might matter, hence we have a fast lookup as well.
private Set> mExistingMappers = new HashSet<>();
private List mMappers = new CopyOnWriteArrayList<>();
public void addMapper(DataBinderMapper mapper) {
Class extends DataBinderMapper> mapperClass = mapper.getClass();
if (mExistingMappers.add(mapperClass)) {
mMappers.add(mapper);
final List dependencies = mapper.collectDependencies();
for(DataBinderMapper dependency : dependencies) {
addMapper(dependency);
}
}
}
这里递归调用addMapper()方法将mapper及其依赖项添加到mExistingMappers及mMappers中。从上面代码可知这里的形参mapper是com.yy.oms.logistics包下的DataBinderMapperImpl类,因此将其添加到map中后,会递归的将其依赖的app下的第二个DataBinderMapperImpl添加到map中。
//com.yy.oms.logistics.DataBinderMapperImpl.java
public List collectDependencies() {
ArrayList result = new ArrayList(3);
result.add(new androidx.databinding.library.baseAdapters.DataBinderMapperImpl());
result.add(new com.yy.oms.baseui.DataBinderMapperImpl());
result.add(new com.yy.oms.home.DataBinderMapperImpl());
return result;
}
可以看到根DataBinderMapperImpl的依赖项有三个,第一个是系统提供的DataBinderMapperImpl,其余两个就是上图中项目编译生成的两外两个DataBinderMapperImpl。总结上述各个节点间的依赖关系为:
将所有节点添加完毕后回到DataBindingUtil的bind()方法中,接下来会调用DataBinderMapperImpl类的getDataBinder()方法,这里会调用到生成的第一个DataBinderMapperImpl的父类MergedDataBinderMapper中的方法:
public ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View view,
int layoutId) {
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集合,再分别调用各个元素的getDataBinder()方法,假设我们要获取home目录下的资源文件的绑定文件,最终会在com.yy.oms.home.DataBinderMapperImpl的getDataBinder()方法中查到结果:
public class DataBinderMapperImpl extends DataBinderMapper {
private static final int LAYOUT_ITEMORDERLIST = 1;
private static final int LAYOUT_ITEMORDERLIST2 = 2;
private static final SparseIntArray INTERNAL_LAYOUT_ID_LOOKUP = new SparseIntArray(2);
static {
INTERNAL_LAYOUT_ID_LOOKUP.put(com.yy.oms.home.R.layout.item_order_list, LAYOUT_ITEMORDERLIST);
INTERNAL_LAYOUT_ID_LOOKUP.put(com.yy.oms.home.R.layout.item_order_list2, LAYOUT_ITEMORDERLIST2);
}
@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_ITEMORDERLIST: {
if ("layout/item_order_list_0".equals(tag)) {
return new ItemOrderListBindingImpl(component, view);
}
throw new IllegalArgumentException("The tag for item_order_list is invalid. Received: " + tag);
}
case LAYOUT_ITEMORDERLIST2: {
if ("layout/item_order_list2_0".equals(tag)) {
return new ItemOrderList2BindingImpl(component, view);
}
throw new IllegalArgumentException("The tag for item_order_list2 is invalid. Received: " + tag);
}
}
}
return null;
}
}
这里会通过tag来获取判断到底返回哪一个绑定,是因为编译器会对xml做处理,看一下item_order_list2.xml处理过后的文件,文件路径为:/Users/zengwenbing/Desktop/WorkSpace/work-xxxxx/xxxxx-android/business/home/build/intermediates/incremental/packageDebugResources/stripped.dir/layout
再对比一下原文件:
通过对比可以有两点结论:
因此可以通过根View的tag来判断到底初始化哪一个绑定,这里会初始化ItemOrderList2BindingImpl实例并返回。下面会执行ItemOrderList2BindingImpl的构造函数:
public ItemOrderList2BindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
this(bindingComponent, root, mapBindings(bindingComponent, root, 10, sIncludes, sViewsWithIds));
}
private ItemOrderList2BindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
super(bindingComponent, root, 0
, (android.widget.TextView) bindings[4]
, (android.widget.ImageView) bindings[9]
, (android.widget.TextView) bindings[7]
, (android.widget.TextView) bindings[3]
, (android.widget.TextView) bindings[2]
, (android.widget.TextView) bindings[6]
, (android.widget.TextView) bindings[5]
, (android.widget.TextView) bindings[1]
, (android.widget.TextView) bindings[8]
);
this.expressNo.setTag(null);
this.logisticsDetail.setTag(null);
this.logisticsNo.setTag(null);
this.mboundView0 = (androidx.constraintlayout.widget.ConstraintLayout) bindings[0];
this.mboundView0.setTag(null);
this.orderStatus.setTag(null);
this.orderTime.setTag(null);
this.paymentAmount.setTag(null);
this.sellerName.setTag(null);
this.updateState.setTag(null);
setRootTag(root);
// listeners
invalidateAll();
}
bindingComponent默认为null,root为根View,mapBindings()函数的作用是将根View通过tag解析并保存在Object[numBindings]中,其下标即是tag中“_”后的数字。看一下解析的过程,代码有点长:
private static void mapBindings(DataBindingComponent bindingComponent, View view,
Object[] bindings, IncludedLayouts includes, SparseIntArray viewsWithIds,
boolean isRoot) {
final int indexInIncludes;
//解析过的View会给其设置tag为R.id.dataBinding(setRootTag()方法),
//这里通过该tag来判断是否已经映射过
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;
//根View的tag以layout开头
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;
}
//子View的tag以binding开头,BINDING_TAG_PREFIX = binding_
} 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;
}
//没有通过xml绑定的,通过传入的viewsWithIds参数进行映射
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;
}
}
}
//对于ViewGroup还要对齐子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;
//映射,其通过类型为IncludedLayouts的includes参数传入
if (indexInIncludes >= 0 && child.getTag() instanceof String) {
String childTag = (String) child.getTag();
//文件中的根View
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;
}
}
}
}
//如果不是,则就是ViewGroup中的子View,就递归调用映射该子View
if (!isInclude) {
mapBindings(bindingComponent, child, bindings, includes, viewsWithIds, false);
}
}
}
}
映射完View,回到ItemOrderList2BindingImpl的构造方法,先调用super()方法,即ItemOrderList2Binding的构造方法:
protected ItemOrderList2Binding(Object _bindingComponent, View _root, int _localFieldCount,
TextView expressNo, ImageView image, TextView logisticsDetail, TextView logisticsNo,
TextView orderStatus, TextView orderTime, TextView paymentAmount, TextView sellerName,
TextView updateState) {
super(_bindingComponent, _root, _localFieldCount);
this.expressNo = expressNo;
this.image = image;
this.logisticsDetail = logisticsDetail;
this.logisticsNo = logisticsNo;
this.orderStatus = orderStatus;
this.orderTime = orderTime;
this.paymentAmount = paymentAmount;
this.sellerName = sellerName;
this.updateState = updateState;
}
这里除了将映射的View设置给ItemOrderList2Binding的成员函数外,还会调用其父类ViewDataBinding的构造函数:
protected ViewDataBinding(DataBindingComponent bindingComponent, View root, int localFieldCount) {
mBindingComponent = bindingComponent;
mLocalFieldObservers = new WeakListener[localFieldCount];
this.mRoot = root;
if (Looper.myLooper() == null) {
throw new IllegalStateException("DataBinding must be created in view's UI Thread");
}
//设置mFrameCallback和mUIThreadHandler用于在主线程执行绑定UI
if (USE_CHOREOGRAPHER) {
mChoreographer = Choreographer.getInstance();
mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
mRebindRunnable.run();
}
};
} else {
mFrameCallback = null;
mUIThreadHandler = new Handler(Looper.myLooper());
}
}
这里主要初始化了mLocalFieldObservers数组,还设置了触发绑定UI时的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()方法执行绑定UI。
获取到绑定后,若要立即执行UI绑定会执行executeBindings():
//class ItemOrderList2BindingImpl
protected void executeBindings() {
java.lang.String mOrderModelOrderSellerName = null;
androidx.databinding.ObservableField mOrderModelTempObservable = null;
if ((dirtyFlags & 0x7L) != 0) {
if ((dirtyFlags & 0x6L) != 0) {
if (mOrderModelOrder != null) {
// read mOrderModel.order.seller_name
mOrderModelOrderSellerName = mOrderModelOrder.getSeller_name();
}
}
if (mOrderModel != null) {
// read mOrderModel.tempObservable
mOrderModelTempObservable = mOrderModel.getTempObservable();
}
updateRegistration(0, mOrderModelTempObservable);
// read androidx.databinding.ViewDataBinding.safeUnbox(mOrderModel.tempObservable.get())
androidxDatabindingViewDataBindingSafeUnboxMOrderModelTempObservableGet = androidx.databinding.ViewDataBinding.safeUnbox(mOrderModelTempObservableGet);
}
// batch finished
if ((dirtyFlags & 0x6L) != 0) {
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.sellerName, mOrderModelOrderSellerName);
}
if ((dirtyFlags & 0x7L) != 0) {
// api target 1
this.logisticsNo.setText(androidxDatabindingViewDataBindingSafeUnboxMOrderModelTempObservableGet);
}
}
删除了冗余代码只留下一个String类型和一个ObservableFile类型的变量。对于String类型的mOrderModelOrderSellerName,每次执行绑定即先读mOrderModel.order.seller_name的值,然后设置给TextVIew sellerName,设置的过程是通过BindingAdapter实现的:
//androidx.databinding.adapters.TextViewBindingAdapter
@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);
}
对于ObservsbleFile类型的变量不仅直接调用TextView的setText()方法设置文字,还需要更新该ObservsbleFile对象注册的监听器:
//ViewDataBinding.java
private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
@Override
public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();
}
};
protected boolean updateRegistration(int localFieldId, Observable observable) {
return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
}
private boolean updateRegistration(int localFieldId, Object observable,
CreateWeakListener listenerCreator) {
//若该localFieldId对应一个null,无意义需要反注册
if (observable == null) {
return unregisterFrom(localFieldId);
}
WeakListener listener = mLocalFieldObservers[localFieldId];
//若本地Field-Observable缓存中以localFieldId为下标不存在WeakListener对象,则需要重新注册
if (listener == null) {
registerTo(localFieldId, observable, listenerCreator);
return true;
}
//若本地Field-Observable缓存中以localFieldId为下标存在WeakListener对象且该对象的target与observable相同,
//则什么都不做
if (listener.getTarget() == observable) {
return false;//nothing to do, same object
}
//若本地Field-Observable缓存中以localFieldId为下标存在WeakListener对象且该对象的target与observable不相同,
//则需要反这册后再重新注册
unregisterFrom(localFieldId);
registerTo(localFieldId, observable, listenerCreator);
return true;
}
以上注释中说明了更新的逻辑,下面来看一反注册与注册的逻辑:
//ViewDataBinding.java
protected boolean unregisterFrom(int localFieldId) {
WeakListener listener = mLocalFieldObservers[localFieldId];
if (listener != null) {
return listener.unregister();
}
return false;
}
//class WeakListener
public boolean unregister() {
boolean unregistered = false;
if (mTarget != null) {
mObservable.removeListener(mTarget);
unregistered = true;
}
mTarget = null;
return unregistered;
}
/************************************************************************************************/
//ViewDataBinding.java
protected void registerTo(int localFieldId, Object observable,
CreateWeakListener listenerCreator) {
if (observable == null) {
return;
}
WeakListener listener = mLocalFieldObservers[localFieldId];
if (listener == null) {
//CREATE_PROPERTY_LISTENER的create()函数会创建一个WeakPropertyListener
listener = listenerCreator.create(this, localFieldId);
mLocalFieldObservers[localFieldId] = listener;
if (mLifecycleOwner != null) {
listener.setLifecycleOwner(mLifecycleOwner);
}
}
listener.setTarget(observable);
}
//class WeakListener
public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
mObservable.setLifecycleOwner(lifecycleOwner);
}
public void setTarget(T object) {
unregister();
mTarget = object;
if (mTarget != null) {
mObservable.addListener(mTarget);
}
}
反注册的逻辑是:
注册的逻辑是:
4. 创建一个类型为WeakPropertyListener的listener;
5. 将该listener添加到mLocalFieldObservers缓存中;
6. 若mLifecycleOwner不为空,则给该listener设置生命周期拥有者;
7. 给该listener设置target。
上一节给WeakPropertyListener设置了target,注意到这里的WeakPropertyListener,UI刷新就是依靠该类型的监听器,除此之外是还有其他类型的监听器,来看看他们的构造函数:
public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
mListener = new WeakListener(binder, localFieldId, this);
}
public WeakListListener(ViewDataBinding binder, int localFieldId) {
mListener = new WeakListener(binder, localFieldId, this);
}
public WeakMapListener(ViewDataBinding binder, int localFieldId) {
mListener = new WeakListener(binder, localFieldId, this);
}
public LiveDataListener(ViewDataBinding binder, int localFieldId) {
mListener = new WeakListener(binder, localFieldId, this);
}
这里的泛型即是WeakListener类中成员变量target的类型,可知这里可以绑定四种类型的targe:Observable、ObservableList、ObservableMap和LiveData。回到上面setTarget()函数,关注mObservable的类型是接口类型ObservableReference,这里我们看两种它的实现:
//class WeakPropertyListener
@Override
public void addListener(Observable target) {
target.addOnPropertyChangedCallback(this);
}
@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);
}
/**************************************************************************************************************/
//class LiveDataListener
@Override
public void addListener(LiveData> target) {
if (mLifecycleOwner != null) {
target.observe(mLifecycleOwner, this);
}
}
@Override
public void onChanged(@Nullable Object o) {
ViewDataBinding binder = mListener.getBinder();
if (binder != null) {
binder.handleFieldChange(mListener.mLocalFieldId, mListener.getTarget(), 0);
}
}
这里可以看到ObservableFile与LiveData的区别是:LiveData需要绑定生命周期拥有者,而ObservableFile不需要。当target的属性发生变化是会调用ViewDataBinding的handleFieldChange()方法来更新UI:
//ViewDataBinding.java
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();
}
}
从注释看当正在进行LiveData的注册时都会触发field的改变,因此无需执行handleFieldChange()。调用虚方法onFieldChange()继续处理,该方法的真正实现在生成类ItemOrderList2BindingImpl中:
//ItemOrderList2BindingImpl.java
@Override
protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
switch (localFieldId) {
case 0 :
return onChangeMOrderModelTempObservable((androidx.databinding.ObservableField) object, fieldId);
}
return false;
}
private boolean onChangeMOrderModelTempObservable(androidx.databinding.ObservableField MOrderModelTempObservable, int fieldId) {
if (fieldId == BR._all) {
synchronized(this) {
mDirtyFlags |= 0x1L;
}
return true;
}
return false;
}
// dirty flag
private long mDirtyFlags = 0xffffffffffffffffL;
/* flag mapping
flag 0 (0x1L): mOrderModel.tempObservable
flag 1 (0x2L): mOrderModel
flag 2 (0x3L): null
flag mapping end*/
在ItemOrderList2BindingImpl的实现方法中只是更新了mDirtyFlags |= 0x1L其余什么都没做,从注释可知mDirtyFlags是用来控制UI更新维度的,这里有两个维度:0x1L代表更新绑定在mOrderModel.tempObservable的UI,0x2L表示更新绑定在mOrderModel上的UI,回顾【DataBinding绑定解析——执行绑定】一节的executeBindings()方法可只UI更新的逻辑。回到ViewDataBinding的handleFieldChange()方法,当onFieldChange()方法返回true表明成功设置了mDirtyFlags可以进行UI绑定了,这是就可以调用requestRebind()方法执行UI绑定了,到此UI绑定完成。