DataBinding源码解析

DataBinding是Google发布的支持库,它可以实现UI组件及数据源的双向绑定。使用DataBinding可以轻松实现MVVM模式,当数据发生变化时会体现在View界面上,反过来界面内容变化也会同步更新到ViewModel中的数据源。同时,在Google推出的Android Jetpack组件中,也将DataBinding放在了Architecture类别之中。

一、DataBinding生成代码
启用DataBinding的方法是在对应Model的build.gradle文件里加入以下代码,同步后就能引入对 DataBinding 的支持。

android {
dataBinding {
enabled = true
}
}
DataBinding的布局文件使用了layout标签作为根节点,其中包含了data标签与view标签view标签。打开xml布局文件,根据DataBinding需要的布局规则进行编写,实例如下:



    




    



Databinding在编译时会生成代码,利用的技术是Apt(annotation-processing-tool)。在我们按照规则编写完xml之后,就会生成相应的java文件,文件名为xml文件名加上Binding后缀,按照上述实例会生成ActivityMainBinding.java文件,其生成的路径为/app/build/generated/source/apt/debug/com/lxbnjupt/databindingdemo/databinding/ActivityMainBinding。

package com.lxbnjupt.databindingdemo.databinding;
import com.lxbnjupt.databindingdemo.R;
import com.lxbnjupt.databindingdemo.BR;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
@SuppressWarnings("unchecked")
public class ActivityMainBinding extends android.databinding.ViewDataBinding {

@Nullable
private static final android.databinding.ViewDataBinding.IncludedLayouts sIncludes;
@Nullable
private static final android.util.SparseIntArray sViewsWithIds;
static {
    sIncludes = null;
    sViewsWithIds = null;
}
// views
@NonNull
private final android.widget.LinearLayout mboundView0;
@NonNull
public final android.widget.TextView tvName;
// variables
@Nullable
private com.lxbnjupt.databindingdemo.UserViewModel mViewmodel;
// values
// listeners
// Inverse Binding Event Handlers

public ActivityMainBinding(@NonNull android.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
    super(bindingComponent, root, 1);
    final Object[] bindings = mapBindings(bindingComponent, root, 2, sIncludes, sViewsWithIds);
    this.mboundView0 = (android.widget.LinearLayout) bindings[0];
    this.mboundView0.setTag(null);
    this.tvName = (android.widget.TextView) bindings[1];
    this.tvName.setTag(null);
    setRootTag(root);
    // listeners
    invalidateAll();
}

@Override
public void invalidateAll() {
    synchronized(this) {
            mDirtyFlags = 0x4L;
    }
    requestRebind();
}

@Override
public boolean hasPendingBindings() {
    synchronized(this) {
        if (mDirtyFlags != 0) {
            return true;
        }
    }
    return false;
}

@Override
public boolean setVariable(int variableId, @Nullable Object variable)  {
    boolean variableSet = true;
    if (BR.viewmodel == variableId) {
        setViewmodel((com.lxbnjupt.databindingdemo.UserViewModel) variable);
    }
    else {
        variableSet = false;
    }
        return variableSet;
}

public void setViewmodel(@Nullable com.lxbnjupt.databindingdemo.UserViewModel Viewmodel) {
    this.mViewmodel = Viewmodel;
    synchronized(this) {
        mDirtyFlags |= 0x2L;
    }
    notifyPropertyChanged(BR.viewmodel);
    super.requestRebind();
}
@Nullable
public com.lxbnjupt.databindingdemo.UserViewModel getViewmodel() {
    return mViewmodel;
}

@Override
protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
    switch (localFieldId) {
        case 0 :
            return onChangeViewmodelName((android.databinding.ObservableField) object, fieldId);
    }
    return false;
}
private boolean onChangeViewmodelName(android.databinding.ObservableField ViewmodelName, int fieldId) {
    if (fieldId == BR._all) {
        synchronized(this) {
                mDirtyFlags |= 0x1L;
        }
        return true;
    }
    return false;
}

@Override
protected void executeBindings() {
    long dirtyFlags = 0;
    synchronized(this) {
        dirtyFlags = mDirtyFlags;
        mDirtyFlags = 0;
    }
    com.lxbnjupt.databindingdemo.UserViewModel viewmodel = mViewmodel;
    java.lang.String viewmodelNameGet = null;
    android.databinding.ObservableField viewmodelName = null;

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



            if (viewmodel != null) {
                // read viewmodel.name
                viewmodelName = viewmodel.name;
            }
            updateRegistration(0, viewmodelName);


            if (viewmodelName != null) {
                // read viewmodel.name.get()
                viewmodelNameGet = viewmodelName.get();
            }
    }
    // batch finished
    if ((dirtyFlags & 0x7L) != 0) {
        // api target 1

        android.databinding.adapters.TextViewBindingAdapter.setText(this.tvName, viewmodelNameGet);
    }
}
// Listener Stub Implementations
// callback impls
// dirty flag
private  long mDirtyFlags = 0xffffffffffffffffL;

@NonNull
public static ActivityMainBinding inflate(@NonNull android.view.LayoutInflater inflater, @Nullable android.view.ViewGroup root, boolean attachToRoot) {
    return inflate(inflater, root, attachToRoot, android.databinding.DataBindingUtil.getDefaultComponent());
}
@NonNull
public static ActivityMainBinding inflate(@NonNull android.view.LayoutInflater inflater, @Nullable android.view.ViewGroup root, boolean attachToRoot, @Nullable android.databinding.DataBindingComponent bindingComponent) {
    return android.databinding.DataBindingUtil.inflate(inflater, com.lxbnjupt.databindingdemo.R.layout.activity_main, root, attachToRoot, bindingComponent);
}
@NonNull
public static ActivityMainBinding inflate(@NonNull android.view.LayoutInflater inflater) {
    return inflate(inflater, android.databinding.DataBindingUtil.getDefaultComponent());
}
@NonNull
public static ActivityMainBinding inflate(@NonNull android.view.LayoutInflater inflater, @Nullable android.databinding.DataBindingComponent bindingComponent) {
    return bind(inflater.inflate(com.lxbnjupt.databindingdemo.R.layout.activity_main, null, false), bindingComponent);
}
@NonNull
public static ActivityMainBinding bind(@NonNull android.view.View view) {
    return bind(view, android.databinding.DataBindingUtil.getDefaultComponent());
}
@NonNull
public static ActivityMainBinding bind(@NonNull android.view.View view, @Nullable android.databinding.DataBindingComponent bindingComponent) {
    if (!"layout/activity_main_0".equals(view.getTag())) {
        throw new RuntimeException("view tag isn't correct on view:" + view.getTag());
    }
    return new ActivityMainBinding(bindingComponent, view);
}
/* flag mapping
    flag 0 (0x1L): viewmodel.name
    flag 1 (0x2L): viewmodel
    flag 2 (0x3L): null
flag mapping end*/
//end

}
二、DataBinding如何避免findViewById
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
}

}
在初始化时,我们利用DataBindingUtil.setContentView()方法来建立layout与ViewDataBinding之间的关系,我们具体看一下该方法的实现。

public static  T setContentView(Activity activity, int layoutId) {
    return setContentView(activity, layoutId, sDefaultComponent);
}
public static  T setContentView(Activity activity, int layoutId,
        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);
}

由源码可知,该方法先是调用了activity.setContentView(layoutId),这个与我们一般在Activity中的使用方式完全一致。接着获取Activity的DecorView,然后再将id为android.R.id.content的view传入bindToAddedViews()方法。

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

static T bind(DataBindingComponent bindingComponent, View root,
int layoutId) {
return (T) sMapper.getDataBinder(bindingComponent, root, layoutId);
}
获取到layout中的根布局,并且调用bind()方法。而bind()方法内调用DataBinderMapper的getDataBinder方法。DataBinderMapper也是编译时生成的类,主要是建立layout与ViewDataBinding之间的映射,其路径为/app/build/generated/source/apt/debug/android/databinding/DataBinderMapper.java。

package android.databinding;
import com.lxbnjupt.databindingdemo.BR;
class DataBinderMapper {
final static int TARGET_MIN_SDK = 18;
public DataBinderMapper() {
}
public android.databinding.ViewDataBinding getDataBinder(android.databinding.DataBindingComponent bindingComponent, android.view.View view, int layoutId) {
switch(layoutId) {
case com.lxbnjupt.databindingdemo.R.layout.activity_main:
return com.lxbnjupt.databindingdemo.databinding.ActivityMainBinding.bind(view, bindingComponent);
}
return null;
}
android.databinding.ViewDataBinding getDataBinder(android.databinding.DataBindingComponent bindingComponent, android.view.View[] views, int layoutId) {
switch(layoutId) {
}
return null;
}
... ...
}
由源码可知,根据layoutId会去调用对应ViewDataBinding的bind()方法。回看一下上一部分中ActivityMainBinding代码,我们可以知道最终会去调用ActivityMainBinding的构造方法,具体如下:

public ActivityMainBinding(@NonNull android.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
    super(bindingComponent, root, 1);
    final Object[] bindings = mapBindings(bindingComponent, root, 2, sIncludes, sViewsWithIds);
    this.mboundView0 = (android.widget.LinearLayout) bindings[0];
    this.mboundView0.setTag(null);
    this.tvName = (android.widget.TextView) bindings[1];
    this.tvName.setTag(null);
    setRootTag(root);
    // listeners
    invalidateAll();
}

我们重点看一下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;
}
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);
            }
        }
    }
}

通过该方法,递归得到最后的bindings数组。如果设置了id的,就将view变量设置为public,这样就避免了findViewById的代码。这种方式从性能上比findViewById更加高效,因为DataBinding只需要遍历一次view的数量,而findViewById多次调用会遍历多次。

三、View与DataBinding之间的双向绑定
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
}

}
我们在Activity中获取了ActivityMainBinding实例,那么很明显View就持有了ViewDataBinding的实例。

通过前面DataBinding如何避免findViewById的源码分析,我们知道在ViewDataBinding的构造方法中会使用mapBindings()方法获取bindings数组,继而通过bindings数组就可以得到各个View,也就是说ViewDataBinding里持有各个View的引用。

至此,View与DataBinding之间的双向绑定关系就建立起来了。

四、ViewModel与DataBinding之间的双向绑定
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    UserViewModel model = new UserViewModel();
    binding.setViewmodel(model);
}

}
我们在Activity中创建了ViewModel的实例,并将它设置到ViewDataBinding中去:

// ActivityMainBinding # setViewmodel
public void setViewmodel(@Nullable com.lxbnjupt.databindingdemo.UserViewModel Viewmodel) {
    this.mViewmodel = Viewmodel;
    synchronized(this) {
        mDirtyFlags |= 0x2L;
    }
    notifyPropertyChanged(BR.viewmodel);
    super.requestRebind();
}

由编译时生成的ActivityMainBinding代码可知,ActivityMainBinding将设置进来的ViewModel赋值给了自己的成员变量,也就意味着ActivityMainBinding中持有了ViewModel。

那么,ViewModel是如何持有ViewDataBinding的呢,这个问题的分析比较复杂。我们看到上面调用的setViewmodel()方法,最后会去调用super.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);
        }
    }
}

这个方法最后会辗转调用到ActivityMainBinding的executeBindings()方法。

@Override
protected void executeBindings() {
    long dirtyFlags = 0;
    synchronized(this) {
        dirtyFlags = mDirtyFlags;
        mDirtyFlags = 0;
    }
    com.lxbnjupt.databindingdemo.UserViewModel viewmodel = mViewmodel;
    java.lang.String viewmodelNameGet = null;
    android.databinding.ObservableField viewmodelName = null;

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



            if (viewmodel != null) {
                // read viewmodel.name
                viewmodelName = viewmodel.name;
            }
            updateRegistration(0, viewmodelName);


            if (viewmodelName != null) {
                // read viewmodel.name.get()
                viewmodelNameGet = viewmodelName.get();
            }
    }
    // batch finished
    if ((dirtyFlags & 0x7L) != 0) {
        // api target 1

        android.databinding.adapters.TextViewBindingAdapter.setText(this.tvName, viewmodelNameGet);
    }
}

我们注意到在这个方法中创建了一个ObservableField对象(即viewmodelName),并将它赋值为ViewModel中的对应对象,之后将它作为参数去调用updateRegistration()方法。

protected boolean updateRegistration(int localFieldId, Observable observable) {
    return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
}

我们先看一下这个CREATE_PROPERTY_LISTENER,它是一个CreateWeakListener对象:

private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
@Override
public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();
}
};
之后调用了updateRegistration的重载方法,在这个重载方法中又会去调用registerTo()方法:

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;
}
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);
}
由源码可知,在registerTo()方法中会调用listenerCreator.create()方法去创建一个WeakListener对象。而这个方法最终会调用上面所提到的CREATE_PROPERTY_LISTENER对象的create()方法。最终创建了一个WeakPropertyListener对象,并调用它的getListener()方法获取WeakListener对象。

private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
implements ObservableReference {
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);
    }
}

由源码可知,在创建WeakPropertyListener对象时,在其构造方法中创建了WeakListener对象,并将其赋值给自己的成员变量,然后又通过开放getListener()方法允许外界获得该WeakListener对象。

private static class WeakListener extends WeakReference {
    private final ObservableReference mObservable;
    protected final int mLocalFieldId;
    private T mTarget;

    public WeakListener(ViewDataBinding binder, int localFieldId,
            ObservableReference observable) {
        super(binder, sReferenceQueue);
        mLocalFieldId = localFieldId;
        mObservable = observable;
    }

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

我们再回到之前的registerTo()方法,该方法中在获取到WeakListener对象之后,便调用了它的setTarget()方法。而在创建WeakListener对象时,其构造方法中的ObservableReference是由WeakPropertyListener中传递过来的,所以setTarget()方法中mObservable.addListener(mTarget)会最终调用到WeakPropertyListener的addListener()方法。我们重点关注一下WeakPropertyListener的几个方法:

@Override
public void addListener(Observable target) {
    target.addOnPropertyChangedCallback(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()方法中的target就是ViewModel中的ObservableField对象,它是一个被观察者。通过addOnPropertyChangedCallback()方法,相当于向target注册一个观察者,在数据源有变化的时候,回调onPropertyChanged()方法。在onPropertyChanged()方法中,又通过WeakListener对象获取ViewDataBinding对象,之后再通过ViewDataBinding对象的handleFieldChange()方法去更新View。通过以上分析,我们可以知道其实ViewModel持有WeakPropertyListener,WeakPropertyListener又持有WeakListener,而WeakListener又持有ViewDataBinding对象(弱引用方式),也就是ViewModel间接地持有了ViewDataBinding。

至此,ViewModel与DataBinding之间的双向绑定关系就建立起来了。

链接:https://www.jianshu.com/p/4be20cc58f17

你可能感兴趣的:(DataBinding源码解析)