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"/>
        <variable
            name="yuanzhen"
            type="YuanZhen"/>
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android: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" />

        <TextView
            android: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"/>
        <EditText
            android: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"?>

                                                       
                                                   

    
                                                                     
                 
                           
                             
           

    <RelativeLayout
        android: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">

        <TextView
            android: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" />

        <TextView
            android: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"/>
        <EditText
            android: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;

    @Override
    protected 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() {
            @Override
            public 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);
    @NonNull
    public List<DataBinderMapper> collectDependencies() {
        // default implementation for backwards compatibility.
        return Collections.emptyList();
    }
}

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

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_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 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;
            }
        }
    }
    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);
    }
    @Bindable
    public String getName() {
        return name;
    }
    @Bindable
    public 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() {
    @Override
    public WeakListener create(
            ViewDataBinding viewDataBinding,
            int localFieldId,
            ReferenceQueue<ViewDataBinding> referenceQueue
    ) {
        return new WeakPropertyListener(viewDataBinding, localFieldId, referenceQueue)
                .getListener();
    }
};

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

private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
        implements ObservableReference<Observable> {
    final WeakListener<Observable> mListener;
    public WeakPropertyListener(
            ViewDataBinding binder,
            int localFieldId,
            ReferenceQueue<ViewDataBinding> referenceQueue
    ) {
        mListener = new WeakListener<Observable>(binder, localFieldId, this, referenceQueue);
    }
    @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) {
    }
    @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);
    }
}

从源码大致可以看出,这个监听器内部创建了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;
    }

    @Nullable
    protected 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() {
            @Override
            public 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() {
    }

    @Override
    public void addOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {
        synchronized (this) {
            if (mCallbacks == null) {
                mCallbacks = new PropertyChangeRegistry();
            }
        }
        mCallbacks.add(callback);
    }

    @Override
    public 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 extends
        CallbackRegistry<Observable.OnPropertyChangedCallback, Observable, Void> {

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

    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 set
    notifyCallbacks(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() {
    @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

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 mPendingHalted
        if (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里面找到它的实现:

    @Override
    protected 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.name
                        yuanzhenName = yuanzhen.getName();
                    }
            }
            if ((dirtyFlags & 0xdL) != 0) {

                    if (yuanzhen != null) {
                        // read yuanzhen.age
                        yuanzhenAge = yuanzhen.getAge();
                    }


                    // read String.valueOf(yuanzhen.age)
                    stringValueOfYuanzhenAge = java.lang.String.valueOf(yuanzhenAge);
            }
        }
        // batch finished
        if ((dirtyFlags & 0xbL) != 0) {
            // api target 1

            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView3, yuanzhenName);
            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.txtName, yuanzhenName);
        }
        if ((dirtyFlags & 0x8L) != 0) {
            // api target 1

            androidx.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 1

            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.txtAge, stringValueOfYuanzhenAge);
        }
    }

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言-枚举

常量符号化 用符号而不是具体的数字来表示程序中的数字 枚举 用枚举而不是定义独立的const int变量 枚举是一种用户定义的数据类型&#xff0c;他用关键词enum以如下语法来声明&#xff1a; enum枚举类型名字{名字0&#xff0c;…&#xff0c;名字n}&#xff1b; 枚举类型名…

HubSpot细分目标市场:拓展业务边界,突破增长瓶颈

在数字化时代&#xff0c;企业面临前所未有的市场挑战。随着科技的飞速发展&#xff0c;消费者期望个性化的体验&#xff0c;即时的互动&#xff0c;以及高质量、有价值的信息。这些变化使得企业不仅需要适应新的技术和趋势&#xff0c;还需要更加精细化地理解和满足不同细分市…

【广州华锐互动】AR昆虫在线教学软件:增强现实技术带你近距离探索微观世界

随着科技的不断发展&#xff0c;教育方式也在不断创新。在这个信息爆炸的时代&#xff0c;传统的教育方式已经无法满足人们对知识的渴望。为了让孩子们更好地了解自然界的奥秘&#xff0c;一款名为“AR昆虫在线教学软件”的应用程序应运而生&#xff0c;它将带领孩子们踏上一段…

HarmonyOS应用开发-手写板

这是一个基于HarmonyOS做的一个手写板应用&#xff0c;只需要简单的几十行代码&#xff0c;就可以实现如下手写功能以及清空画布功能。 一、先上效果图&#xff1a; 二、上代码 Entry Component struct Index {//手写路径State pathCommands: string ;build() {Column() {//…

kubeadm搭建单master多node的k8s集群--小白文,图文教程

参考文献 K8S基础知识与集群搭建 kubeadm搭建单master多node的k8s集群—主要参考这个博客&#xff0c;但是有坑&#xff0c;故贴出我自己的过程&#xff0c;坑会少很多 注意&#xff1a; 集群配置是&#xff1a;一台master&#xff1a;zabbixagent-k8smaster&#xff0c;两台…

基于YOLOv7算法的高精度实时烟头目标检测识别系统(PyTorch+Pyside6+YOLOv7)

摘要&#xff1a;基于YOLOv7算法的高精度实时烟头目标检测系统可用于日常生活中检测与定位烟头目标&#xff0c;此系统可完成对输入图片、视频、文件夹以及摄像头方式的目标检测与识别&#xff0c;同时本系统还支持检测结果可视化与导出。本系统采用YOLOv7目标检测算法来训练数…

重磅!2023中国高校计算机大赛-人工智能创意赛结果出炉

目录 中国计算机大赛-人工智能创意赛现场C4-AI大赛颁奖及留影800个AI应用&#xff1f;这届大学生真能“搞事情”AI原生时代&#xff0c;百度要再培养500万大模型人才 中国计算机大赛-人工智能创意赛现场 12月8日&#xff0c;杭州&#xff0c;一位“白发老人”突然摔倒在地&…

halcon一维测量

标定的作用&#xff1a; 得到相机的内参和外参&#xff0c;即相机成像的模型规律 * fuse.hdev: measuring the width of a fuse wire * dev_update_window (off) dev_close_window () * **** * step: acquire image * **** read_image (Fuse, fuse) get_image_size (Fuse, Wid…

公交站间的距离

&#x1f388; 算法并不一定都是很难的题目&#xff0c;也有很多只是一些代码技巧&#xff0c;多进行一些算法题目的练习&#xff0c;可以帮助我们开阔解题思路&#xff0c;提升我们的逻辑思维能力&#xff0c;也可以将一些算法思维结合到业务代码的编写思考中。简而言之&#…

LeetCode 279完全平方数 139单词拆分 卡码网 56携带矿石资源(多重背包) | 代码随想录25期训练营day45

动态规划算法6 LeetCode 279 完全平方数 2023.12.11 题目链接代码随想录讲解[链接] int numSquares(int n) {//1确定dp数组&#xff0c;其下标表示j的完全平方数的最少数量//3初始化&#xff0c;将dp[0]初始化为0&#xff0c;用于计算&#xff0c;其他值设为INT_MAX用于递推…

C++联合体union

联合体 将多个类型合并到一起省空间 枚举与联合一起使用 匿名联合 类似于无作用域 &#xff23;11联合体定义非内建类型 C11 引入了能够在联合体中使用非内建类型的能力&#xff0c;这些类型包括具有自定义构造函数、析构函数、拷贝构造函数和拷贝赋值运算符的类。 关键特性…

STM32F407-14.1.0-01高级定时器简介

TIM1 和 TIM8 简介 高级控制定时器&#xff08;TIM1 和 TIM8&#xff09;包含一个 16 位自动重载计数器&#xff0c;该计数器由可编程预分频器驱动。 此类定时器可用于各种用途&#xff0c;包括测量输入信号的脉冲宽度&#xff08;输入捕获&#xff09;&#xff0c;或者生成输出…

软件运行原理 - 内存模型 - 栈内存

说明 C/C软件运行时&#xff0c;内存根据使用方式的不同分为堆内存和栈内存&#xff0c;栈内存使用有以下特征&#xff1a; 栈内存使用&#xff08;申请、释放&#xff09;由系统自动分配和释放&#xff0c;程序员不用做任何操作。栈内存重复使用&#xff0c;进入函数时数据入…

Axure安装及面板各区域详解

目录 一、Axure简介 二、Axure安装及使用准备 2.1 Axure官网 2.2 Axure授权 2.3 Axure汉化 2.4 设置RP文件保存路径 三、Axure菜单栏的使用 3.1 新建项目 3.2 新建元件库 3.3 自动备份设置 3.4 页面画布网格设置 四、Axure工具栏 4.1 选择模式 4.1.1 相交选中 4…

基于Qt的登录页面设计

题目&#xff1a; 完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果账号和…

CyclicBarrier、CountDownLatch、Semaphore 的用法

CyclicBarrier、CountDownLatch、Semaphore 的用法 CountDownLatch&#xff08;线程计数器 &#xff09; CountDownLatch 类位于 java.util.concurrent 包下&#xff0c;利用它可以实现类似计数器的功能。比如有一个任务 A&#xff0c;它要等待其他 4 个任务执行完毕之后才能执…

建筑可视化数据大屏汇总,UI源文件(PC端大屏设计)

酷炫的大屏设计让数据更好的展现&#xff0c;方便业务人员分析数据&#xff0c;辅助领导决策。现在分享大屏Photoshop源文件&#xff0c;以下为部分截图示意。 划重点&#xff1a;文末可获得完整素材包~ 01 科技建筑平台数据可视化 02 建筑公司可视化数据汇总平台 03 深蓝…

软件开发流程分析

软件开发流程分析 相关概念1 原型设计2 产品设计3 交互设计4 代码实现详细步骤 相关概念 前端&#xff1a;自研API&#xff0c;调用第三放API 后端&#xff1a;自研API&#xff0c;第三方API 数据库&#xff1a;Mysql&#xff0c;数据采集&#xff0c;数据迁移 服务器&#xf…

软件兼容性测试:保障多样化用户体验的重要功能

随着移动设备和操作系统的快速发展&#xff0c;软件兼容性测试变得越发重要。这项测试确保软件在不同平台、设备和环境下都能够正常运行&#xff0c;提供一致而稳定的用户体验。下面是软件兼容性测试中的一些关键功能&#xff1a; 1. 跨平台兼容性测试 在不同操作系统上运行的软…

Shopify二次开发之五:元字段(Metafields)

目录 解释 操作 1、添加Custom data 2、选择特定类型的数据 3、为Page配置元子段和值 4、模板访问 解释 Shopify Metafields 是一种用于存储和管理自定义数据的功能。它们允许商户在商城中的产品、订单、客户、Page等对象上添加自定义字段&#xff0c;以满足特定业务需求…