databinding源码分析一

来源:互联网 发布:灯具品牌 知乎 编辑:程序博客网 时间:2024/06/16 09:42

前言

databinding是google在2015年发布的一个库,支持布局文件和mode数据之间进行绑定。最新版本已经支持双向绑定,数据的更新可以触发同步到布局对应的ui界面,布局文件的数据更新也可以传递到mode数据上。

1. 数据更新如何触发ui更新的?

2. ui操作是如何关联上数据的?

3. 自定义view该如何关联数据绑定?

带着以上三个问题分析源码,本篇先分析问题一:

源码

databinding源码分为两个组成部分:
Android/sdk/extras/android/m2repository/com/android/databinding

1. library

2. adapters

library为databinding核心组建代码,包括BaseObservable,DataBinderMapper,ViewDataBinding等

adapters定义了常用ui控件在与mode数据绑定时的适配器,如果是自定义控件,可以参照来编写。

以mvvm架构的天气工程为例子,clone代码到本地,切换到mvvm-databinding分之代码。

该工程代码使用了mvvm框架的架构,view和 mode关联是通过databinding框架在实现。在WeatherViewMode类定义了用来表示天气文本信息的字符串mWeatherinfo。

public class WeatherViewMode extends BaseObservable {    public final ObservableField<String> mWeatherinfo = new ObservableField<>();

这个字符通过
ObservableField进行了包装。对应的布局文件

<layout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto">    <data>        <import type="android.view.View" />        <variable            name="view"            type="com.android_app_architecture_demo.weather.WeatherFragment" />        <variable            name="viewmodel"            type="com.android_app_architecture_demo.weather.WeatherViewMode" />    </data>    <FrameLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        >        <TextView            android:id="@+id/weather_info"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@{viewmodel.mWeatherinfo}" />    </FrameLayout></layout>

在布局文件声明了关联的view和viewmode,view对应的类是WeatherFragment

 @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        // Inflate the layout for this fragment        mFragmentWeatherBinding = FragmentWeatherBinding.inflate(inflater,container,false);        mFragmentWeatherBinding.setView(this);        mFragmentWeatherBinding.setViewmodel(mViewModel);        View root = mFragmentWeatherBinding.getRoot();        return root;    }

可以看到在WeatherFragment中通过FragmentWeatherBinding的类对当前view和viewmode进行了关联绑定。FragmentWeatherBinding这个类是编译过程中自动生成的,继承自ViewDataBinding。进入FragmentWeatherBinding来看一下具体绑定操作流程:

  public FragmentWeatherBinding(android.databinding.DataBindingComponent bindingComponent, View root) {        ...        // listeners        invalidateAll();    }    @Override    public void invalidateAll() {        synchronized(this) {                mDirtyFlags = 0x8L;        }        requestRebind();    }

FragmentWeatherBinding构造函数里面调用了invalidateAll进行界面刷新,进去发现是通过requestRebind来实现view的注册,view和viewmode之间的绑定。

protected void executeBindings() {    ...        updateRegistration(1, viewmodelMWeatherinfo);    ...    }

在requestRebind会最终调用executeBindings,executeBindings注册了天气信息viewmodelMWeatherinfo,对应的id是1。view和viewmode的id在后续的操作流程里面会继续使用到。

 public void setViewmodel(com.android_app_architecture_demo.weather.WeatherViewMode Viewmodel) {        //注册viewmode,对应id为0        updateRegistration(0, Viewmodel);        this.mViewmodel = Viewmodel;        synchronized(this) {            mDirtyFlags |= 0x1L;        }        notifyPropertyChanged(BR.viewmodel);        super.requestRebind();    }

setViewmodel方法里面注册viewmode,对应id为0。
updateRegistration(1,viewmodelMWeatherinfo)调用了父类ViewDataBinding的注册方法

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

其中CREATE_PROPERTY_LISTENER表示普通对象属性的监听器,对应的还有list和map对应的监听器,本例中只定义了一个String,因此匹配的是CREATE_PROPERTY_LISTENER。

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

addListener是用来添加监听器

onPropertyChanged监听器回调,handleFieldChange用来处理对象属性数据变化以后的ui更新,后面再详细来看触发流程。现继续来分析注册监听器的流程

 private 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;    }
 /**     * @hide     */    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);            mLocalFieldObservers[localFieldId] = listener;        }        listener.setTarget(observable);    }     public void setTarget(T object) {            unregister();            mTarget = object;            if (mTarget != null) {                mObservable.addListener(mTarget);            }        }   @Override        public void addListener(Observable target) {            target.addOnPropertyChangedCallback(this);        }

至此完成listner注册。

回头来看onPropertyChanged回调是如何触发ui进行更新的?以ObservableField为例,

public class ObservableField<T> extends BaseObservable implements Serializable {    static final long serialVersionUID = 1L;    private T mValue;
  /**     * Set the stored value.     */    public void set(T value) {        if (value != mValue) {            mValue = value;            notifyChange();        }    }

当更改ObservableField的数据内容时候,会触发notifyChange,直接调用父类BaseObservable的实现

 /**     * Notifies listeners that all properties of this instance have changed.     */    public void notifyChange() {        synchronized (this) {            if (mCallbacks == null) {                return;            }        }        mCallbacks.notifyCallbacks(this, 0, null);    }

这里面的callback是什么呢?

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

callback是OnPropertyChangedCallback,就是WeakPropertyListener里面的监听器。onPropertyChanged监听器回调,handleFieldChange用来处理ui更新。

 private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {        boolean result = onFieldChange(mLocalFieldId, object, fieldId);        if (result) {            requestRebind();        }    }

首先调用onFieldChange(mLocalFieldId, object, fieldId),在本示例中,当天气信息变化,mLocalFieldId就是mWeatherinfo对应的id,object就是mWeatherinfo,fieldId在这里是0。

@Override    protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {        switch (localFieldId) {            case 0 :                return onChangeViewmodel((com.android_app_architecture_demo.weather.WeatherViewMode) object, fieldId);            case 1 :                return onChangeViewmodelMWeatherinfo((android.databinding.ObservableField<java.lang.String>) object, fieldId);        }        return false;    }

在onFieldChange处理中,首先检查localFieldId的值,在这里对应的是mWeatherinfo的id为1,继续调用
onChangeViewmodelMWeatherinfo。

 private boolean onChangeViewmodelMWeatherinfo(android.databinding.ObservableField<java.lang.String> ViewmodelMWeatherinfo, int fieldId) {        switch (fieldId) {            case BR._all: {                synchronized(this) {                        mDirtyFlags |= 0x2L;                }                return true;            }        }        return false;    }

检测到天气信息数据变化,设置mDirtyFlags |= 0x2L来标记。

handleFieldChange方法中判断,如果onChangeViewmodelMWeatherinfo返回true,即有数据更新,就开始调用requestRebind()

 protected void requestRebind() {        if (mContainingBinding != null) {            mContainingBinding.requestRebind();        } else {            synchronized (this) {                if (mPendingRebind) {                    return;                }                mPendingRebind = true;            }            if (USE_CHOREOGRAPHER) {                mChoreographer.postFrameCallback(mFrameCallback);            } else {                 mUIThreadHandler.post(mRebindRunnable);            }        }    }

最终通过UI线程mUIThreadHandler将数据刷新到对应的view上。
最终调用到FragmentWeatherBinding实现的方法executeBindings,这里完成UI的重新绘制。

 @Override    protected void executeBindings() {        long dirtyFlags = 0;        synchronized(this) {            dirtyFlags = mDirtyFlags;            mDirtyFlags = 0;        }        java.lang.String viewmodelMWeatherinfoGet = null;        com.android_app_architecture_demo.weather.WeatherViewMode viewmodel = mViewmodel;        android.databinding.ObservableField<java.lang.String> viewmodelMWeatherinfo = null;        if ((dirtyFlags & 0xbL) != 0) {                if (viewmodel != null) {                    // read viewmodel.mWeatherinfo                    viewmodelMWeatherinfo = viewmodel.mWeatherinfo;                }                updateRegistration(1, viewmodelMWeatherinfo);                if (viewmodelMWeatherinfo != null) {                    // read viewmodel.mWeatherinfo.get()                    viewmodelMWeatherinfoGet = viewmodelMWeatherinfo.get();                }        }        // batch finished        if ((dirtyFlags & 0xbL) != 0) {            // api target 1            android.databinding.adapters.TextViewBindingAdapter.setText(this.weatherInfo, viewmodelMWeatherinfoGet);        }    }

总结

通过上文分析,可以大致看出databinding是如何注册管理view、viewmode,并且当viewmode数据更新如何通过监听器回调触发UI界面的更新。

原创粉丝点击