DataBinding是如何实现数据变化视图更新的——源码分析

在使用databinding时,更新UI界面,如果是使用普通变量的,那么在变量发生变化的时候,UI界面并不会发生变化

一、数据绑定

视图跟随数据刷新

数据变化是视图也跟着变化则需要使用到以下两种方法

  1. 继承BaseObservable
  2. ObservableField,databinding默认实现了一系列实现Observable接口的字段类型
BaseObservable,
ObservableBoolean,
ObservableByte,
ObservableChar,
ObservableDouble,
ObservableField<T>,
ObservableFloat,
ObservableInt,
ObservableLong,
ObservableParcelable<T extends Parcelable>,
ObservableShort,
ViewDataBinding
  1. MutableLiveData
    Android 最近推出的Android Jetpack 其中的livedata也支持数据更新时,视图也能更新。

为了方便我们暂且把这种可以让视图跟随数据刷新的类型,叫做databinding变量
这里不再介绍这些,可以去网上搜相关内容或者参考链接

数据跟随视图刷新

通过表达式使用@=表达式就可以视图刷新的时候自动更新数据

这种双向绑定存在一个很大的问题就是会死循环。 数据变化(回调监听器)触发视图变化, 然后视图又会触发数据变化(再次回调监听器), 然后一直循环, 设置相同的数据也视为数据变化.

二、源码分析

为什么使用这些变量,视图可以根据数据而变化呢?双向绑定的时候,是如何避免死循环的呢?在使用databinding时,经常遇到各种错误,如果对源码熟悉,就可以迅速定位问题并解决。所以理解源码是很有必要的。

更新视图的源码,主要按变量类型分为四类, Observable ,ObservableList ,ObservableMap ,LiveData<?> 源码大同小异,这里以ObservableField为例进行分析

ObservableField更新视图源码分析

编译后,会自动在路app\build\generated\source\kapt\debug\com\xhd\xiaohuangdian\databinding\FragmentAbstractTotalBindingImpl.java生成对应的代码,其中主干流程就是下面三个函数。

DataBinding 使用观察者模式,当数据发生变化的时候,对UI进行更新,那么我们看一下观察者注册订阅者的流程

1、设置变量,让变量此时的值显示到UI上

    @Override
    public boolean setVariable(int variableId, @Nullable Object variable)  {
        boolean variableSet = true;
        if (BR.fragment == variableId) {
            setFragment((com.xhd.xiaohuangdian.ui.home.AbstractTotalFragment) variable);
        }
        else if (BR.viewModel == variableId) {
            setViewModel((com.xhd.xiaohuangdian.vm.home.TotalVM) variable);
        }
        else {
            variableSet = false;
        }
            return variableSet;
    }


	//如果Fragment类中,没有其他的databinding变量,会生成如下的setxxxxx函数
    public void setFragment(@Nullable com.xhd.xiaohuangdian.ui.home.AbstractTotalFragment Fragment) {
        this.mFragment = Fragment;
    }
	//如果ViewModel类中,有其他的databinding变量,会生成如下的setxxxxx函数
    public void setViewModel(@Nullable com.xhd.xiaohuangdian.vm.home.TotalVM ViewModel) {
        this.mViewModel = ViewModel;
        synchronized(this) {
            mDirtyFlags |= 0x4L;
        }
        notifyPropertyChanged(BR.viewModel);
        //这行代码,最后会执行到executeBindings()
        super.requestRebind();
    }

2、在executeBindings中进行 订阅,数据发生变化也会调用。

    @Override
    protected void executeBindings() {
        long dirtyFlags = 0;
        synchronized(this) {
            //脏标志位,初始的脏标志位为全1,为了让下面所有的if都可以执行,非第一次执行(数据改变后的执行),会根据这个脏标志位来判断执行那个if
            dirtyFlags = mDirtyFlags;
            mDirtyFlags = 0;
        }
        boolean viewModelIsLoadingGet = false;
        androidx.databinding.ObservableBoolean viewModelIsLoading = null;
        com.xhd.xiaohuangdian.vm.home.TotalVM viewModel = mViewModel;

        if ((dirtyFlags & 0xdL) != 0) {

                if (viewModel != null) {
                    // read viewModel.isLoading
                    viewModelIsLoading = viewModel.isLoading();
                }
                //在这里进行订阅
                updateRegistration(0, viewModelIsLoading);


                if (viewModelIsLoading != null) {
                    // read viewModel.isLoading.get()
                    viewModelIsLoadingGet = viewModelIsLoading.get();
                }
        }
        // batch finished
        if ((dirtyFlags & 0xdL) != 0) {
            // api target 1

            this.mboundView0.setPbEnable(viewModelIsLoadingGet);
        }
        executeBindingsOn(mboundView0);
    }

观察者订阅和更新UI都是通过上面这个函数来完成,
如果你看了代码,会有疑问,难道每次更新数据的是否都会去再订阅一次吗?
是的,因为这个观察者是个弱引用,很可能被系统回收了,所以每次更新数据时都会再去订阅一次。如果订阅关系没有发生变化,则直接返回false(详解下面的代码)

3、updateRegistration(0, viewModelIsLoading);可以理解为创建了一个监听。
updateRegistration 有四种类型,主要就是参数类型不一样,四种参数分别对应于Observable ,ObservableList ,ObservableMap ,LiveData<?>,也就是上面所说的databinding变量

源码如下:

    /**
     * @hide
     */
    protected boolean updateRegistration(int localFieldId, Observable observable) {
        return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
    }

    /**
     * @hide
     */
    protected boolean updateRegistration(int localFieldId, ObservableList observable) {
        return updateRegistration(localFieldId, observable, CREATE_LIST_LISTENER);
    }

    /**
     * @hide
     */
    protected boolean updateRegistration(int localFieldId, ObservableMap observable) {
        return updateRegistration(localFieldId, observable, CREATE_MAP_LISTENER);
    }

    /**
     * @hide
     */
    protected boolean updateLiveDataRegistration(int localFieldId, LiveData<?> observable) {
        mInLiveDataRegisterObserver = true;
        try {
            return updateRegistration(localFieldId, observable, CREATE_LIVE_DATA_LISTENER);
        } finally {
            mInLiveDataRegisterObserver = false;
        }
    }

上面updateRegistration的第三个参数是CreateWeakListener 接口类型的。只有一个create()函数,返回类型是WeakListener

    /**
     * Method object extracted out to attach a listener to a bound Observable object.
     */
    private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
        @Override
        public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
            return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();
        }
    };

    /**
     * Method object extracted out to attach a listener to a bound ObservableList object.
     */
    private static final CreateWeakListener CREATE_LIST_LISTENER = new CreateWeakListener() {
        @Override
        public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
            return new WeakListListener(viewDataBinding, localFieldId).getListener();
        }
    };

    /**
     * Method object extracted out to attach a listener to a bound ObservableMap object.
     */
    private static final CreateWeakListener CREATE_MAP_LISTENER = new CreateWeakListener() {
        @Override
        public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
            return new WeakMapListener(viewDataBinding, localFieldId).getListener();
        }
    };

    /**
     * Method object extracted out to attach a listener to a bound LiveData object.
     */
    private static final CreateWeakListener CREATE_LIVE_DATA_LISTENER = new CreateWeakListener() {
        @Override
        public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
            return new LiveDataListener(viewDataBinding, localFieldId).getListener();
        }
    };

4、WeakListener 是在WeakPropertyListener 里面创建的

    private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
            implements ObservableReference<Observable> {
        final WeakListener<Observable> mListener;

        public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
            mListener = new WeakListener<Observable>(binder, localFieldId, this);
        }

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

		//数据更新后,回调到这里去更新UI,下接第12段
        @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 有一个WeakPropertyListener类型的变量mObservable, 是一个弱引用类,防止内存泄漏。所以后面的操作,都是通过它的对象来操作。

    private static 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) {
            super(binder, sReferenceQueue);
            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;
        }

        protected ViewDataBinding getBinder() {
            ViewDataBinding binder = get();
            if (binder == null) {
                unregister(); // The binder is dead
            }
            return binder;
        }
    }

5、回到 第三点,开始继续分析 updateRegistration 的源码,最终去执行registerTo

   // observable  参数是ObservableBoolean  类型的,是业务中的值
   // listenerCreator 上面四种CreateWeakListener 之一,通过它的create 可以获取到WeakListener ,WeakListener 的参数mObservable 是WeakPropertyListener类型
    private boolean updateRegistration(int localFieldId, Object observable,
            CreateWeakListener listenerCreator) {
        if (observable == null) {
            return unregisterFrom(localFieldId);
        }
        //将WeakListener  变量保存在mLocalFieldObservers 因为WeakListener是弱引用,所以需要判空,如果是空的就注册
        WeakListener listener = mLocalFieldObservers[localFieldId];
        if (listener == null) {
            registerTo(localFieldId, observable, listenerCreator);
            return true;
        }
        //listener 和相同的tatget 注册过了,就不需要再注册了
        if (listener.getTarget() == observable) {
            return false;//nothing to do, same object
        }
        unregisterFrom(localFieldId);
        //进行注册
        registerTo(localFieldId, observable, listenerCreator);
        return true;
    }

6、注册监听,如果WeakListener 为空,就是通过listenerCreator.create(this, localFieldId);来创建WeakListener ,最后调用 listener.setTarget(observable);

    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);
            //这里把新创建的WeakListener 保存在数组,方便下次使用 
            mLocalFieldObservers[localFieldId] = listener;
            if (mLifecycleOwner != null) {
                listener.setLifecycleOwner(mLifecycleOwner);
            }
        }
        //listener 是WeakListener ,
        listener.setTarget(observable);
    }

7、分析一下,上段代码listener.setTarget(observable); 就是调用WeakListenersetTarget

WeakListener中的setTarget

	   //这里的T 参数是ObservableBoolean  类型的,是业务中的值
       public void setTarget(T object) {
           unregister();
            mTarget = object;
            if (mTarget != null) {
               // mObservable 就是WeakPropertyListener
               // 通过WeakListener 里面的参数来使用WeakPropertyListener,就是保证WeakListener 可以在内存吃紧的时候,可以被回收
                mObservable.addListener(mTarget);
            }
       }

调用了WeakPropertyListeneraddListener

        @Override
        public void addListener(Observable target) {
           //参数是`OnPropertyChangedCallback` 类型,这里传入的参数是this,因为**WeakPropertyListener**变量,实现了接口`OnPropertyChangedCallback` 
           //target 是Observable 类型 (ObservableBoolean的父类)
            target.addOnPropertyChangedCallback(this);
        }

8、target.addOnPropertyChangedCallback(this);调用了BaseObservableaddOnPropertyChangedCallback函数

public class BaseObservable implements Observable {
    private transient PropertyChangeRegistry mCallbacks;

    public BaseObservable() {
    }

	//这里的参数callback,就是WeakPropertyListener变量,因为它实现了接口OnPropertyChangedCallback 
    @Override
    public void addOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {
        synchronized (this) {
            if (mCallbacks == null) {
                mCallbacks = new PropertyChangeRegistry();
            }
        }
        //终于到了观察者订阅的地方,(本例子来看,BaseObservable 就是ObservableBoolean)
        // 相当于把一个观察者 callback,与订阅者BaseObservable  ,建立联系,当BaseObservable 的数据发生变化,通知到callback,实现相应的UI更新
        mCallbacks.add(callback);
    }

     ...省略部分函数...

    /**
     * Notifies listeners that all properties of this instance have changed.
     * databinding 变量的数据发生变化后,最先会调用到这里
     */
    public void notifyChange() {
        synchronized (this) {
            if (mCallbacks == null) {
                return;
            }
        }
        //这一句代码,最终会调用到下面的第9点的callback.onPropertyChanged(sender, arg);
        mCallbacks.notifyCallbacks(this, 0, null);
    }

    ...省略部分函数...
}

9、上面的创建了PropertyChangeRegistry,来看一下它都做了些什么

  • 实现了一个接口到变量NOTIFIER_CALLBACK
  • 这个类是继承CallbackRegistry,调用 super(NOTIFIER_CALLBACK);把这个接口的实现,传递给CallbackRegistry的变量mNotifier,mNotifier主要是在databinding变量数据更新后,回调的时候使用,下面会介绍到。
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) {
            //数据更新后,调用WeakPropertyListener的onPropertyChanged()
            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);
    }
}

10、观察者就已经订阅好了,接下来看一下,如果数据发生变化,是怎么去更新UI的。

数据发生变化,例如调用:ObservableField系列的set()

    public void set(boolean value) {
        //这里的判断,避免了双向绑定的死循环
        if (value != mValue) {
            mValue = value;
            //数据更新后,这个函数就是第8段代码的notifyChange()
            notifyChange();
        }
    }

11、第8段代码的notifyChange()调用的mCallbacks.notifyCallbacks(this, 0, null);最终会到下面这段代码,这里的mNotifier就是第9段代码的PropertyChangeRegistry 的父类变量

    private void notifyCallbacks(T sender, int arg, A arg2, final int startIndex,
            final int endIndex, final long bits) {
        long bitMask = 1;
        for (int i = startIndex; i < endIndex; i++) {
            if ((bits & bitMask) == 0) {
            //数据更新后,调用PropertyChangeRegistry中的接口变量的函数
                mNotifier.onNotifyCallback(mCallbacks.get(i), sender, arg, arg2);
            }
            bitMask <<= 1;
        }
    }

12、分析一下mNotifier.onNotifyCallback,其中mNotifier 就是PropertyChangeRegistry 中的NOTIFIER_CALLBACK(看第9段代码),调用callback.onPropertyChanged(sender, arg);——>调用第4段中的WeakPropertyListener的onPropertyChanged()

13、第4段代码中的, binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);调用了下面的这个函数,onFieldChange()是一个抽象函数,它的实现类,就是编译时候生成的xxxxxBindingImpl.java,因此就是调用第2段代码中的onFieldChange(),判断是否需要改变,最终在 requestRebind();中调用了第3段代码 executeBindings()实现了对UI的更新

    private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
        if (mInLiveDataRegisterObserver) {
            // We're in LiveData registration, which always results in a field change
            // that we can ignore. The value will be read immediately after anyway, so
            // there is no need to be dirty.
            return;
        }
        boolean result = onFieldChange(mLocalFieldId, object, fieldId);
        if (result) {
            requestRebind();
        }
    }

14、onFieldChange 回调到 XXXXBindingImpl.java 类中调用

    @Override
    protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
        switch (localFieldId) {
            case 0 :
                return onChangeViewModelIsLoading((androidx.databinding.ObservableBoolean) object, fieldId);
        }
        return false;
    }

    private boolean onChangeViewModelIsLoading(androidx.databinding.ObservableBoolean ViewModelIsLoading, int fieldId) {
        if (fieldId == BR._all) {
            synchronized(this) {
                    //脏标志位,数据更新后,用于在第三段代码中判断哪些if语句需要执行
                    mDirtyFlags |= 0x1L;
            }
            return true;
        }
        return false;
    }

15、来看一下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;
            }
            //boolean USE_CHOREOGRAPHER = SDK_INT >= 16;
            if (USE_CHOREOGRAPHER) {
                mChoreographer.postFrameCallback(mFrameCallback);
            } else {
                mUIThreadHandler.post(mRebindRunnable);
            }
        }
    }

注意这里更新UI是异步的,所以在java代码中,更新databinding的数据,之后马上又去设置ui值,可能最后会被databinding的值覆盖。
异步执行的Runnable ,代码如下

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

下面的代码很简单,看注释的那几句关键代码

    public void executePendingBindings() {
        if (mContainingBinding == null) {
           //执行了这句代码
            executeBindingsInternal();
        } else {
            mContainingBinding.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) {
            //这里最终会调用到第三段代码,对UI进行更新
            executeBindings();
            if (mRebindCallbacks != null) {
                mRebindCallbacks.notifyCallbacks(this, REBOUND, null);
            }
        }
        mIsExecutingPendingBindings = false;
    }

这介绍了databinding的主要流程,其中包括一些其他的细节,例如脏标志位mDirtyFlags,LifecycleOwner等等,在这个基础上去理解这些细节会容易一些。

©️2020 CSDN 皮肤主题: 撸撸猫 设计师: 设计师小姐姐 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值