Android--Jetpack--Databinding源码解析

慢品人间烟火色,闲观万事岁月长

一,基本使用

关于databinding的基本使用请看之前的文章

Android--Jetpack--Databinding详解-CSDN博客

二,xml布局解析

分析源码呢,主要就是从两方面入手,一个是使用,一个是APT生成的代码。

我们看一下上一篇文章我们的布局xml文件:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"><data class="MyDataBing"><import type="com.yuanzhen.lifecycledemo.databing.YuanZhen"/><variablename="yuanzhen"type="YuanZhen"/></data><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TextViewandroid:id="@+id/txt_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{yuanzhen.name}"android:textSize="40sp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><TextViewandroid:id="@+id/txt_age"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="40sp"android:text="@{String.valueOf(yuanzhen.age)}"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"android:layout_below="@+id/txt_name"/><EditTextandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/txt_age"android:textSize="40sp"android:text="@={yuanzhen.name}"/></RelativeLayout>
</layout>

然后我们看一下APT生成的代码:

打开之后,格式化一下,看看代码:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Layout bindingClass="MyDataBing" directory="layout"filePath="app\src\main\res\layout\activity_main.xml" isBindingData="true"isMerge="false" layout="activity_main" modulePackage="com.yuanzhen.lifecycledemo"rootNodeType="android.widget.RelativeLayout"><ClassNameLocation endLine="5" endOffset="26" startLine="5" startOffset="17" /><Variables name="yuanzhen" declared="true" type="YuanZhen"><location endLine="9" endOffset="28" startLine="7" startOffset="8" /></Variables><Imports name="YuanZhen" type="com.yuanzhen.lifecycledemo.databing.YuanZhen"><location endLine="6" endOffset="68" startLine="6" startOffset="8" /></Imports><Targets><Target tag="layout/activity_main_0" view="RelativeLayout"><Expressions /><location endLine="48" endOffset="20" startLine="12" startOffset="4" /></Target><Target id="@+id/txt_name" tag="binding_1" view="TextView"><Expressions><Expression attribute="android:text" text="yuanzhen.name"><Location endLine="21" endOffset="42" startLine="21" startOffset="12" /><TwoWay>false</TwoWay><ValueLocation endLine="21" endOffset="40" startLine="21" startOffset="28" /></Expression></Expressions><location endLine="26" endOffset="55" startLine="17" startOffset="8" /></Target><Target id="@+id/txt_age" tag="binding_2" view="TextView"><Expressions><Expression attribute="android:text" text="String.valueOf(yuanzhen.age)"><Location endLine="33" endOffset="57" startLine="33" startOffset="12" /><TwoWay>false</TwoWay><ValueLocation endLine="33" endOffset="55" startLine="33" startOffset="28" /></Expression></Expressions><location endLine="38" endOffset="49" startLine="28" startOffset="8" /></Target><Target tag="binding_3" view="EditText"><Expressions><Expression attribute="android:text" text="yuanzhen.name"><Location endLine="44" endOffset="43" startLine="44" startOffset="12" /><TwoWay>true</TwoWay><ValueLocation endLine="44" endOffset="41" startLine="44" startOffset="29" /></Expression></Expressions><location endLine="44" endOffset="45" startLine="39" startOffset="8" /></Target></Targets>
</Layout>

我们发现每个view都包装了一个Targets标签,对应了一个tag。

比如RelativeLayout对应的是layout/activity_main_0

然后看看我们的textview:

<Target id="@+id/txt_name" tag="binding_1" view="TextView"><Expressions><Expression attribute="android:text" text="yuanzhen.name"><Location endLine="21" endOffset="42" startLine="21" startOffset="12" /><TwoWay>false</TwoWay><ValueLocation endLine="21" endOffset="40" startLine="21" startOffset="28" /></Expression></Expressions><location endLine="26" endOffset="55" startLine="17" startOffset="8" />
</Target>

 通过text将yuanzhen.name赋值给了textview

然后在打开另一个APT生成的文件:

看看它的代码:

<?xml version="1.0" encoding="utf-8"?><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" android:tag="layout/activity_main_0" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"><TextViewandroid:id="@+id/txt_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:tag="binding_1"        android:textSize="40sp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><TextViewandroid:id="@+id/txt_age"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="40sp"android:tag="binding_2"                       app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"android:layout_below="@+id/txt_name"/><EditTextandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/txt_age"android:textSize="40sp"android:tag="binding_3"         /></RelativeLayout>

上面空了一大块,把布局文件的layout去掉了,其余的和我们的布局文件一样,除此之外,它给每个view都增加了一个tag,这个tag与上面的tag一一对应,这就是布局的解析。

三,xml代码解析

首先我们看一下上一章我们的使用代码:

public class MainActivity extends AppCompatActivity {private MyDataBing dataBinding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);YuanZhen yuanZhen =new YuanZhen("袁震",18);dataBinding.setYuanzhen(yuanZhen);new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 10; i++) {try {Thread.sleep(1000);yuanZhen.setName(yuanZhen.getName()+i);yuanZhen.setAge(18+i);} catch (InterruptedException e) {e.printStackTrace();}}}}).start();}}

首先,我们看一下dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)这句代码的实现,它会走到DataBindingUtil的setContentView():

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) {activity.setContentView(layoutId);View decorView = activity.getWindow().getDecorView();ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content);return bindToAddedViews(bindingComponent, contentView, 0, layoutId);
}

前三行代码我们应该都能看懂

获取到了conetntView,并传入了方法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);}
}

该方法会调用bind(component, children, layoutId)方法:

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

然后会调用  sMapper.getDataBinder(bindingComponent, root, layoutId):

public abstract class DataBinderMapper {public abstract ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View view,int layoutId);public abstract ViewDataBinding getDataBinder(DataBindingComponent bindingComponent,View[] view, int layoutId);public abstract int getLayoutId(String tag);public abstract String convertBrIdToString(int id);@NonNullpublic List<DataBinderMapper> collectDependencies() {// default implementation for backwards compatibility.return Collections.emptyList();}
}

然后查看getDataBinder的引用,会找到APT生成的DataBinderMapperImpl类的getDataBinder方法:

public class DataBinderMapperImpl extends DataBinderMapper {。。。@Overridepublic 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_ACTIVITYMAIN: {if ("layout/activity_main_0".equals(tag)) {return new MyDataBingImpl(component, view);}throw new IllegalArgumentException("The tag for activity_main is invalid. Received: " + tag);}}}return null;
}
。。。}

这里比较关键的代码是:如果我们传过来的tag是layout/activity_main_0,就是前面生成的xml里面的根节点的tag,那么就创建我们自定义命名的MyDataBingImpl。

然后我们查看MyDataBingImpl的构造函数:

public MyDataBingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {this(bindingComponent, root, mapBindings(bindingComponent, root, 4, sIncludes, sViewsWithIds));
}

会发现这里有个4,4的意思就是xml文件里面的4个view节点。

继续往下看mapBindings源码:

protected static Object[] mapBindings(DataBindingComponent bindingComponent, View root,int numBindings, IncludedLayouts includes, SparseIntArray viewsWithIds) {Object[] bindings = new Object[numBindings];mapBindings(bindingComponent, root, bindings, includes, viewsWithIds, true);return bindings;
}

 创建了一个大小为4的对象数组,然后调用mapBindings:

private static void mapBindings(DataBindingComponent bindingComponent, View view,Object[] bindings, IncludedLayouts includes, SparseIntArray viewsWithIds,boolean isRoot) {final int indexInIncludes;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)) {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)) {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 viewindexInIncludes = -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;}}}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;if (indexInIncludes >= 0 && child.getTag() instanceof String) {String childTag = (String) child.getTag();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;}}}}if (!isInclude) {mapBindings(bindingComponent, child, bindings, includes, viewsWithIds, false);}}}
}

这段源码主要是通过tag解析出view,放到数组里面。

这样我们在使用的时候,就能拿到xml里面的view了:

这样xml的代码解析就完成了。

四,核心原理

databinding的核心逻辑就是更新数据的同时自动更新UI。那么我们可以判断出它的整体实际上肯定是一个观察者模式。首先被观察者肯定是数据类,就是我们的YuanZhen这个类:

public class YuanZhen extends BaseObservable {public YuanZhen(String name, int age) {this.name = name;this.age = age;}private String name;private int age;public void setName(String name) {this.name = name;notifyPropertyChanged(BR.name);}public void setAge(int age) {this.age = age;notifyPropertyChanged(BR.age);}@Bindablepublic String getName() {return name;}@Bindablepublic int getAge() {return age;}
}

它继承了BaseObservable并且在数据发生变化的时候调用了notify方法,通知观察者去更新UI。

 所以观察者肯定是更新ui的类,就是我们APT生成的MyDataBingImpl这个类。

中间肯定会有注册和反注册观察者的逻辑。下面我们还是先从使用入手分析:

我们来看下这句代码:dataBinding.setYuanzhen(yuanZhen) ,它是初始化的代码,直接点击是找不到的,它是在APT生成的MyDataBingImpl类里面:

@SuppressWarnings("unchecked")
public class MyDataBingImpl extends MyDataBing  {。。。。public void setYuanzhen(@Nullable com.yuanzhen.lifecycledemo.databing.YuanZhen Yuanzhen) {updateRegistration(0, Yuanzhen);this.mYuanzhen = Yuanzhen;synchronized(this) {mDirtyFlags |= 0x1L;}notifyPropertyChanged(BR.yuanzhen);super.requestRebind();}}

先来看updateRegistration(0, Yuanzhen):

protected boolean updateRegistration(int localFieldId, Observable observable) {return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
}

先看看第三个参数: CREATE_PROPERTY_LISTENER,从名字可以看出,它是创建Property监听器的,看看它的源码:

private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {@Overridepublic WeakListener create(ViewDataBinding viewDataBinding,int localFieldId,ReferenceQueue<ViewDataBinding> referenceQueue) {return new WeakPropertyListener(viewDataBinding, localFieldId, referenceQueue).getListener();}
};

果然是创建了一个WeakPropertyListener,看看它的源码:

private static class WeakPropertyListener extends Observable.OnPropertyChangedCallbackimplements ObservableReference<Observable> {final WeakListener<Observable> mListener;public WeakPropertyListener(ViewDataBinding binder,int localFieldId,ReferenceQueue<ViewDataBinding> referenceQueue) {mListener = new WeakListener<Observable>(binder, localFieldId, this, referenceQueue);}@Overridepublic WeakListener<Observable> getListener() {return mListener;}@Overridepublic void addListener(Observable target) {target.addOnPropertyChangedCallback(this);}@Overridepublic void removeListener(Observable target) {target.removeOnPropertyChangedCallback(this);}@Overridepublic void setLifecycleOwner(LifecycleOwner lifecycleOwner) {}@Overridepublic 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);}
}

从源码大致可以看出,这个监听器内部创建了WeakListener   并且将WeakListenter和 ViewDataBinding,localFieldId进行绑定,并在调用onPropertyChanged方法时,调用ViewDataBinding的handleFieldChange方法,并将WeakListenter的mLocalFieldId传给后者。

然后看下WeakListener   的源码:

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class WeakListener<T> extends WeakReference<ViewDataBinding> {private final ObservableReference<T> mObservable;protected final int mLocalFieldId;private T mTarget;public WeakListener(ViewDataBinding binder,int localFieldId,ObservableReference<T> observable,ReferenceQueue<ViewDataBinding> referenceQueue) {super(binder, referenceQueue);mLocalFieldId = localFieldId;mObservable = observable;}public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {mObservable.setLifecycleOwner(lifecycleOwner);}public void setTarget(T object) {unregister();mTarget = object;if (mTarget != null) {mObservable.addListener(mTarget);}}public boolean unregister() {boolean unregistered = false;if (mTarget != null) {mObservable.removeListener(mTarget);unregistered = true;}mTarget = null;return unregistered;}public T getTarget() {return mTarget;}@Nullableprotected ViewDataBinding getBinder() {ViewDataBinding binder = get();if (binder == null) {unregister(); // The binder is dead}return binder;}
}

 在WeakListener   里面主要是将ViewDataBinding和localFieldId进行了绑定

然后我们再继续看updateRegistration的源码:

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
protected boolean updateRegistration(int localFieldId, Object observable,CreateWeakListener listenerCreator) {if (observable == null) {return unregisterFrom(localFieldId);}WeakListener listener = mLocalFieldObservers[localFieldId];if (listener == null) {registerTo(localFieldId, observable, listenerCreator);return true;}if (listener.getTarget() == observable) {return false;//nothing to do, same object}unregisterFrom(localFieldId);registerTo(localFieldId, observable, listenerCreator);return true;
}
mLocalFieldObservers[localFieldId]:看看它是什么时候创建的
private WeakListener[] mLocalFieldObservers;
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");}if (USE_CHOREOGRAPHER) {mChoreographer = Choreographer.getInstance();mFrameCallback = new Choreographer.FrameCallback() {@Overridepublic void doFrame(long frameTimeNanos) {mRebindRunnable.run();}};} else {mFrameCallback = null;mUIThreadHandler = new Handler(Looper.myLooper());}
}

原来是在我们上面讲的xml代码解析里面初始化ViewDataBinding的时候创建的:

public MyDataBingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {this(bindingComponent, root, mapBindings(bindingComponent, root, 4, sIncludes, sViewsWithIds));
}

并且数组的大小是4。这个4是怎么来的呢?

继续返回MyDataBingImpl的setYuanzhen方法往下看:

notifyPropertyChanged(BR.yuanzhen);

看一下BR这个类,也是APT生成的:

public class BR {public static final int _all = 0;public static final int age = 1;public static final int name = 2;public static final int yuanzhen = 3;
}

主要就是将属性用数字定义了。数组的大小 就是这个类的属性的数量。

再返回头来看updateRegistration:如果WeakLister不存在,就走registerTo(localFieldId, observable, listenerCreator);方法:

protected void registerTo(int localFieldId, Object observable,CreateWeakListener listenerCreator) {if (observable == null) {return;}WeakListener listener = mLocalFieldObservers[localFieldId];if (listener == null) {listener = listenerCreator.create(this, localFieldId, sReferenceQueue);mLocalFieldObservers[localFieldId] = listener;if (mLifecycleOwner != null) {listener.setLifecycleOwner(mLifecycleOwner);}}listener.setTarget(observable);
}

这个方法主要是通过上面创建的CreateWeakListener来创建WeakListener,并将WeakListener放入mLocalFieldObservers数组中它对应的位置。

看完了初始化绑定关系,再来看看被观察者BaseObservable:

public class BaseObservable implements Observable {private transient PropertyChangeRegistry mCallbacks;public BaseObservable() {}@Overridepublic void addOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {synchronized (this) {if (mCallbacks == null) {mCallbacks = new PropertyChangeRegistry();}}mCallbacks.add(callback);}@Overridepublic void removeOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {synchronized (this) {if (mCallbacks == null) {return;}}mCallbacks.remove(callback);}/*** Notifies listeners that all properties of this instance have changed.*/public void notifyChange() {synchronized (this) {if (mCallbacks == null) {return;}}mCallbacks.notifyCallbacks(this, 0, null);}/*** Notifies listeners that a specific property has changed. The getter for the property* that changes should be marked with {@link Bindable} to generate a field in* <code>BR</code> to be used as <code>fieldId</code>.** @param fieldId The generated BR id for the Bindable field.*/public void notifyPropertyChanged(int fieldId) {synchronized (this) {if (mCallbacks == null) {return;}}mCallbacks.notifyCallbacks(this, fieldId, null);}
}

首先看mCallbacks的源码:

public class PropertyChangeRegistry extendsCallbackRegistry<Observable.OnPropertyChangedCallback, Observable, Void> {private static final CallbackRegistry.NotifierCallback<Observable.OnPropertyChangedCallback, Observable, Void> NOTIFIER_CALLBACK = new CallbackRegistry.NotifierCallback<Observable.OnPropertyChangedCallback, Observable, Void>() {@Overridepublic void onNotifyCallback(Observable.OnPropertyChangedCallback callback, Observable sender,int arg, Void notUsed) {callback.onPropertyChanged(sender, arg);}};public PropertyChangeRegistry() {super(NOTIFIER_CALLBACK);}/*** Notifies registered callbacks that a specific property has changed.** @param observable The Observable that has changed.* @param propertyId The BR id of the property that has changed or BR._all if the entire*                   Observable has changed.*/public void notifyChange(@NonNull Observable observable, int propertyId) {notifyCallbacks(observable, propertyId, null);}
}

可以看出它主要是用来通知观察者更新消息的。

我们调用notifyPropertyChanged就会调用PropertyChangeRegistry的notifyChange方法。

然后依次往下调用:

public synchronized void notifyCallbacks(T sender, int arg, A arg2) {mNotificationLevel++;notifyRecurse(sender, arg, arg2);mNotificationLevel--;if (mNotificationLevel == 0) {if (mRemainderRemoved != null) {for (int i = mRemainderRemoved.length - 1; i >= 0; i--) {final long removedBits = mRemainderRemoved[i];if (removedBits != 0) {removeRemovedCallbacks((i + 1) * Long.SIZE, removedBits);mRemainderRemoved[i] = 0;}}}if (mFirst64Removed != 0) {removeRemovedCallbacks(0, mFirst64Removed);mFirst64Removed = 0;}}
}

之后notifyRecurse

private void notifyRecurse(T sender, int arg, A arg2) {final int callbackCount = mCallbacks.size();final int remainderIndex = mRemainderRemoved == null ? -1 : mRemainderRemoved.length - 1;// Now we've got all callbakcs that have no mRemainderRemoved value, so notify the// others.notifyRemainder(sender, arg, arg2, remainderIndex);// notifyRemainder notifies all at maxIndex, so we'd normally start at maxIndex + 1// However, we must also keep track of those in mFirst64Removed, so we add 2 instead:final int startCallbackIndex = (remainderIndex + 2) * Long.SIZE;// The remaining have no bit setnotifyCallbacks(sender, arg, arg2, startCallbackIndex, callbackCount, 0);
}

然后:

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) {mNotifier.onNotifyCallback(mCallbacks.get(i), sender, arg, arg2);}bitMask <<= 1;}
}

然后看看NotifierCallback

public abstract static class NotifierCallback<C, T, A> {/*** Called by CallbackRegistry during* {@link CallbackRegistry#notifyCallbacks(Object, int, Object)}} to notify the callback.** @param callback The callback to notify.* @param sender The opaque sender object.* @param arg The opaque notification parameter.* @param arg2 An opaque argument passed in*        {@link CallbackRegistry#notifyCallbacks}* @see CallbackRegistry#CallbackRegistry(CallbackRegistry.NotifierCallback)*/public abstract void onNotifyCallback(C callback, T sender, int arg, A arg2);
}

之后又回到了PropertyChangeRegistry的回调里面:

public class PropertyChangeRegistry extends CallbackRegistry<Observable.OnPropertyChangedCallback, Observable, Void> {private static final CallbackRegistry.NotifierCallback<Observable.OnPropertyChangedCallback, Observable, Void> NOTIFIER_CALLBACK = new CallbackRegistry.NotifierCallback<Observable.OnPropertyChangedCallback, Observable, Void>() {public void onNotifyCallback(Observable.OnPropertyChangedCallback callback, Observable sender, int arg, Void notUsed) {callback.onPropertyChanged(sender, arg);}};public PropertyChangeRegistry() {super(NOTIFIER_CALLBACK);}public void notifyChange(@NonNull Observable observable, int propertyId) {this.notifyCallbacks(observable, propertyId, (Object)null);}
}

 然后继续往下走onPropertyChanged

public interface Observable {/*** Adds a callback to listen for changes to the Observable.* @param callback The callback to start listening.*/void addOnPropertyChangedCallback(OnPropertyChangedCallback callback);/*** Removes a callback from those listening for changes.* @param callback The callback that should stop listening.*/void removeOnPropertyChangedCallback(OnPropertyChangedCallback callback);/*** The callback that is called by Observable when an observable property has changed.*/abstract class OnPropertyChangedCallback {/*** Called by an Observable whenever an observable property changes.* @param sender The Observable that is changing.* @param propertyId The BR identifier of the property that has changed. The getter*                   for this property should be annotated with {@link Bindable}.*/public abstract void onPropertyChanged(Observable sender, int propertyId);}
}

 

@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);
}

继续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 (USE_CHOREOGRAPHER) {mChoreographer.postFrameCallback(mFrameCallback);} else {mUIThreadHandler.post(mRebindRunnable);}}
}

然后看看mRebindRunnable里面:

private final Runnable mRebindRunnable = new Runnable() {@Overridepublic 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 IntelliJif (!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

private void executeBindingsInternal() {if (mIsExecutingPendingBindings) {requestRebind();return;}if (!hasPendingBindings()) {return;}mIsExecutingPendingBindings = true;mRebindHalted = false;if (mRebindCallbacks != null) {mRebindCallbacks.notifyCallbacks(this, REBIND, null);// The onRebindListeners will change mPendingHaltedif (mRebindHalted) {mRebindCallbacks.notifyCallbacks(this, HALTED, null);}}if (!mRebindHalted) {executeBindings();if (mRebindCallbacks != null) {mRebindCallbacks.notifyCallbacks(this, REBOUND, null);}}mIsExecutingPendingBindings = false;
}

看看executeBindings():

protected abstract void executeBindings();

然后在MyDataBingImpl里面找到它的实现:

    @Overrideprotected void executeBindings() {long dirtyFlags = 0;synchronized(this) {dirtyFlags = mDirtyFlags;mDirtyFlags = 0;}java.lang.String yuanzhenName = null;com.yuanzhen.lifecycledemo.databing.YuanZhen yuanzhen = mYuanzhen;int yuanzhenAge = 0;java.lang.String stringValueOfYuanzhenAge = null;if ((dirtyFlags & 0xfL) != 0) {if ((dirtyFlags & 0xbL) != 0) {if (yuanzhen != null) {// read yuanzhen.nameyuanzhenName = yuanzhen.getName();}}if ((dirtyFlags & 0xdL) != 0) {if (yuanzhen != null) {// read yuanzhen.ageyuanzhenAge = yuanzhen.getAge();}// read String.valueOf(yuanzhen.age)stringValueOfYuanzhenAge = java.lang.String.valueOf(yuanzhenAge);}}// batch finishedif ((dirtyFlags & 0xbL) != 0) {// api target 1androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView3, yuanzhenName);androidx.databinding.adapters.TextViewBindingAdapter.setText(this.txtName, yuanzhenName);}if ((dirtyFlags & 0x8L) != 0) {// api target 1androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.mboundView3, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, mboundView3androidTextAttrChanged);}if ((dirtyFlags & 0xdL) != 0) {// api target 1androidx.databinding.adapters.TextViewBindingAdapter.setText(this.txtAge, stringValueOfYuanzhenAge);}}

看到上面的最终数据的改变也是通过调用setText等方法来实现的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/266329.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

D28|买卖股票的最佳时机+跳跃游戏

122.买卖股票的最佳时机 II 初始思路&#xff1a; 这道题解题的时候比较像在找规律&#xff0c;发现只要计算这个过程中的两数之差然后相加即可。 题解复盘&#xff1a; 可以更加清晰的发现如何从题意中获得贪心的思路。 如何贪心&#xff1a;局部最优&#xff1a;收集每天的…

mybatis多表映射-延迟加载,延迟加载的前提条件是:分步查询

1、建库建表 create database mybatis-example; use mybatis-example; create table t_book (bid varchar(20) primary key,bname varchar(20),stuid varchar(20) ); insert into t_book values(b001,Java,s001); insert into t_book values(b002,Python,s002); insert into …

2024美赛备战2--模型建立(*****必看****)

建模 美赛涉及的建模知识范围非常广且深&#xff0c;纵观美赛真题不难发现&#xff0c;很多的模型 都是读研或者读博的时候才会真正深入开始研究&#xff0c;因此&#xff0c;对于做建模的同学来说&#xff0c; 是无法在赛前吃透大量模型的。推荐本科生分两个步骤去有效准备比赛…

SpringBootWeb请求响应之前言及状态码的详细解析

SpringBootWeb请求响应 前言 在上一次的课程中&#xff0c;我们开发了springbootweb的入门程序。 基于SpringBoot的方式开发一个web应用&#xff0c;浏览器发起请求 /hello 后 &#xff0c;给浏览器返回字符串 “Hello World ~”。 其实呢&#xff0c;是我们在浏览器发起请求…

外包干了3个月,技术退步明显。。。

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

搜集怎么绘制三维曲线和曲面?

1、针对函数对象是单一变量、两个函数的情况。用plot3函数&#xff1b;&#xff08;三维曲线&#xff09; 看一下matlab官方的例子&#xff1a; t 0:pi/50:10*pi; st sin(t); ct cos(t); plot3(st,ct,t) 绘制出来的曲线&#xff1a; 几个比较关键的点&#xff1a; &…

NV040D语音芯片应用于取暖桌:智能语音提高用户体验

科技与生活的结合&#xff0c;是科技发展的展示。天气的降温&#xff0c;取暖桌越来越取得用户的心&#xff0c;时至今日传统的取暖桌已经没有办法满足用户的需求&#xff0c;智能语音取暖桌给用户的生活带来了不一样的体验。 NV040D语音芯片是一款性能稳定的芯片&#xff0c;拥…

客户案例:EDLP在央国企邮件数据合规中的价值与优势

客户背景 某机械制造企业&#xff0c;作为动力设备领域的领军企业&#xff0c;专门从事动力设备的研发、制造与销售。凭借丰富的经验与卓越的技术实力&#xff0c;该企业致力于深度研究动力设备的核心技术&#xff0c;为客户提供高效且可靠的解决方案。 客户需求 作为企业健康…

什么是特征图?

在卷积神经网络&#xff08;CNN&#xff09;中&#xff0c;特征图是在传递给卷积层的图像上发生卷积操作后卷积层的输出。 特征图是如何形成的&#xff1f; 在上面的插图中&#xff0c;我们可以看到特征图是如何从提供的输入图像中形成的。 要发送到卷积层的图像是一个包含像…

.NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(测试篇)

WebAppDbTest 项目测试 测试工具 ltt介绍安装使用方式1、Drill2、Hammer3、Nailgun 测试主机规格配置CRUD 性能测试对比1、ltt 工具测试1.1、AddSingle 单条数据添加1.2、AddBulk 批量数据&#xff08;1000&#xff09;条添加1.3、GetSingle 单条数据查询1.4、GetAll 多条&…

文件误删危机!同事操作失误,老板情急之下该如何处理?

近期&#xff0c;一则企业员工误删数据事件引发热议。 &#xff08;截图源自网络&#xff09; 起因是某公司员工被公司辞退后&#xff0c;已经做完交接就离开了公司。而3天后&#xff0c;新来的员工不小心把这位同事原本办公电脑里的资料给删除了&#xff0c;且由于没有进行数…

<JavaEE> 锁进阶 -- 锁策略(乐观锁和悲观锁、重量级锁和轻量级锁、自旋锁和挂起等待锁、可重入锁和不可重入锁、公平锁和非公平锁、读写锁)

目录 一、锁策略介绍 二、乐观锁和悲观锁 三、轻量级锁和重量级锁 四、自旋锁和挂起等待锁 五、公平锁和非公平锁 六、可重入锁和不可重入锁 七、读写锁 一、锁策略介绍 加锁的目的是为了保证线程安全&#xff0c;根据不同的实际情况&#xff0c;锁也会有不同的策略来应…