Android--Jetpack--Databinding源码解析

news2024/12/26 22:26:30

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

一,基本使用

关于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等方法来实现的。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nginx正则表达式

目录 1.nginx常用的正则表达式 2.location location 大致可以分为三类 location 常用的匹配规则 location 优先级 location 示例说明 优先级总结 3.rewrite rewrite功能 rewrite跳转实现 rewrite执行顺序 语法格式 rewrite示例 实例1&#xff1a; 实例2&#xf…

Vue3封装一个轮播图组件

先看效果 编写组件代码 CarouselChart.vue <template><div classimg-box><el-button clickpreviousImages v-ifprops.showBtn>←</el-button><div classimg><div styledisplay: flex;gap: 20px idmove><imgclassimg-item v-for(item…

hdlbits系列verilog解答(Ringer)-55

文章目录 一、问题描述二、verilog源码三、仿真结果 一、问题描述 本次我们设计一个电路以实现对手机铃声和振动的控制。当工作在振动模式时&#xff0c;开启振动&#xff0c;否则开启铃声。 尝试只使用assign语句&#xff0c;测试一下你是否能将描述转化成数字逻辑电路。 二…

Guava反射工具详解

第1章&#xff1a;引言 大家好&#xff0c;我是小黑&#xff0c;今天咱们聊聊Java反射&#xff0c;特别是在Guava这个强大的库中&#xff0c;它是怎么让反射变得更简单&#xff0c;更有趣的。咱们都知道&#xff0c;反射在Java中是个相当强大的特性&#xff0c;它允许程序在运…

基于ssm的校园快递一站式服务系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本校园快递一站式服务系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数…

【Java 基础】30 JDK动态代理

文章目录 1.定义2.原理3.使用1&#xff09;定义业务接口2&#xff09;实现 InvocationHandler 接口3&#xff09;生成代理类 4.优点5.缺点总结 动态代理是一种重要的 设计模式&#xff0c;它允许在运行时生成代理类来代替实际的类。动态代理主要通过反射机制实现&#xff0c;为…

计算机图形学——消隐算法

目录 消隐算法 &#xff08;1&#xff09;隐藏线消除算法 &#xff08;2&#xff09;隐藏面消除算法 曲面体消隐算法 3D Mesh 隐藏面消除算法 &#xff08;1&#xff09;深度缓冲器算法&#xff08;zBuffer&#xff09; 深度缓冲器 &#xff08;2&#xff09;深度排序…

机器学习基础介绍

百度百科&#xff1a; 机器学习是一门多领域交叉学科&#xff0c;涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为&#xff0c;以获取新的知识或技能&#xff0c;重新组织已有的知识结构使之不断改善自身的性能。 …

mysql 链接超时的几个参数详解

mysql5.7版本中&#xff0c;先查看超时设置参数&#xff0c;我们这里只关注需要的超时参数&#xff0c;并不是全都讲解 show variables like %timeout%; connect_timeout 指的是连接过程中握手的超时时间,在5.0.52以后默认为10秒&#xff0c;之前版本默认是5秒&#xff0c;主…

学习人工智能-基础篇

背景 随着大模型的火爆&#xff0c;人工智能再次被推到高潮&#xff0c;其实它在众多行业领域已经落地很多应用&#xff0c;并给社会带来了巨大的经济价值。其中包括互联网、教育、金融、医疗、交通、物流等等。在测试领域也有一些落地的案例&#xff0c;作为测试人员&#xf…

关于个人职业选择

职业选择&#xff0c;一直是个老生常谈的话题。这并不是一个容易做的决定。 让我们来看看AI怎么说。 首先是方向性的回答&#xff1a; 然后是一些具体的回答 我个人比较倾向于深耕网络安全。这是一个很有趣也是一个持续发展着的领域。 不知道关于这个事情你怎么看&#xff0…

案例解决Redis高并发场景带来的缓存穿透、击穿、雪崩问题(超级详细!!)

假设你的网站流量量达到亿级&#xff0c;传统的去查询DB势必会给DB带来巨大的压力&#xff0c;甚至可能有宕机的风险&#xff0c;接下来我就分几个阶段&#xff0c;来讲诉各个场景可能会给DB带来巨大压力的可能&#xff0c;以及优化的方案。 缓存击穿&#xff1a;key对应的数据…

2023年12月11日:ui界面跳转

头文件&#xff1a;Second #ifndef SECOND_H #define SECOND_H#include <QWidget>namespace Ui { class Second; }class Second : public QWidget {Q_OBJECTpublic:explicit Second(QWidget *parent nullptr);~Second(); public slots:void jump_slot(); private:Ui::S…

飞桨星河文心SDK与open interpreter构成“小天网”雏形

飞桨星河文心SDK与open interpreter构成“小天网”雏形 开放式解释器open interpreter是大模型和自然语言交互的神器&#xff0c;本项目旨在体验文心大模型为底座的open interpreter。本项目只需使用CPU环境即可运行&#xff0c;直接运行即可“运行全部Cell”&#xff0c;本项…

访问控制列表ACL学习

ACL概念 ACL: ACL 是 Access Control List&#xff08;访问控制列表&#xff09;的缩写。它是一种用于管理和控制访问权限的机制或数据结构。ACL 用于确定谁可以访问特定资源&#xff08;例如文件、文件夹、网络资源等&#xff09;以及他们可以执行的操作。ACL 通常由一系列访…

【EMNLP 2023】面向Stable Diffusion的自动Prompt工程算法

近日&#xff0c;阿里云人工智能平台PAI与华南理工大学朱金辉教授团队合作在自然语言处理顶级会议EMNLP2023上发表了BeautifulPrompt的深度生成模型&#xff0c;可以从简单的图片描述中生成高质量的提示词&#xff0c;从而使文生图模型能够生成更美观的图像。BeautifulPrompt通…

1、混合方式UI设计

1、混合方式UI设计 新建项目添加静态资源添加资源添加action添加菜单菜单栏工具栏中间编辑区域 代码添加其他组件字体和大小状态栏 添加槽函数UI设置的转到槽的手写的设置应用程序图标 代码 新建项目 MainWindow代码文件夹主窗口为 (QMainWindow) 添加静态资源 AppIcon.icoi…

【MATLAB】基于CEEMDAN分解的信号去噪算法(基础版)

代码的使用说明 【MATLAB】基于CEEMDAN分解的信号去噪算法&#xff08;基础版&#xff09; 代码流程图 代码效果图 获取代码请关注MATLAB科研小白的个人公众号&#xff08;即文章下方二维码&#xff09;&#xff0c;并回复CEEMDAN去噪 本公众号致力于解决找代码难&#xff0c;…

【C++】POCO学习总结(十二):流(文本编解码、数据压缩、文件读写流等)

【C】郭老二博文之&#xff1a;C目录 1、说明 POCO提供了多种流类&#xff0c;与标准c IOStreams兼容。 大多数POCO流类被实现为过滤器&#xff0c;这意味着它们不写入或读取设备&#xff0c;而是从它们连接的另一个流。 2、文本编解码 2.1 说明 POCO提供了用于编码和解码…

苹果文本动态高亮,滚动时候部分高亮不显示问题

很简单的需求&#xff1a; 一个文本容器固定大小&#xff0c;内容超出滚动&#xff0c;然后文本点击高亮&#xff0c;奇怪就是苹果微信打开会出现点击只会高亮能看见的区域文本&#xff0c;滚动部分不会显示&#xff0c;默认浏览器打开也不行&#xff0c;安卓没问题&#xff0…