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 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 mListener;
public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
mListener = new WeakListener(binder, localFieldId, this);
}
@Override
public WeakListener 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) object, fieldId);
}
return false;
}
在onFieldChange处理中,首先检查localFieldId的值,在这里对应的是mWeatherinfo的id为1,继续调用
onChangeViewmodelMWeatherinfo。
private boolean onChangeViewmodelMWeatherinfo(android.databinding.ObservableField 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 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界面的更新。