美文网首页
Android架构组件之DataBinding源码解析

Android架构组件之DataBinding源码解析

作者: lxbnjupt | 来源:发表于2018-12-04 18:05 被阅读0次

    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需要的布局规则进行编写,实例如下:

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">
    
        <data>
            <variable
                name="viewmodel"
                type="com.lxbnjupt.databindingdemo.UserViewModel"/>
        </data>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <TextView
                android:id="@+id/tv_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{viewmodel.name.get()}" />
    
        </LinearLayout>
    </layout>
    

    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<java.lang.String>) object, fieldId);
            }
            return false;
        }
        private boolean onChangeViewmodelName(android.databinding.ObservableField<java.lang.String> 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<java.lang.String> 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.<ActivityMainBinding>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 extends ViewDataBinding> T setContentView(Activity activity, int layoutId) {
            return setContentView(activity, layoutId, sDefaultComponent);
        }
        public static <T extends ViewDataBinding> 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 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);
        }
    }
    
    static <T extends ViewDataBinding> 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<java.lang.String> 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<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);
            }
        }
    

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

        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 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<T>是由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之间的双向绑定关系就建立起来了。

    相关文章

      网友评论

          本文标题:Android架构组件之DataBinding源码解析

          本文链接:https://www.haomeiwen.com/subject/arhvcqtx.html