Android DataBinding双向绑定原理

DataBinding双向绑定

示例xml如下:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="user"
            type="com.cnstrong.jetpackexercise.User" />
        <variable
            name="profile"
            type="com.cnstrong.jetpackexercise.Profile" />
    </data>

    <androidx.appcompat.widget.LinearLayoutCompat
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <androidx.appcompat.widget.AppCompatTextView
            android:layout_width="match_parent"
            android:layout_height="70dp"
            android:text='@{"name = " + user.name + "\t\t\t age = " + user.age}' /> // model -> view

        <androidx.appcompat.widget.AppCompatEditText
            android:layout_width="match_parent"
            android:layout_height="70dp"
            android:text="@={user.name}" />  // 双向

        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/user_bt"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:layout_marginTop="20dp"
            android:onClick="setUser"
            android:text="set" />

        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/user_change_bt"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:layout_marginTop="20dp"
            android:onClick="changeUser"
            android:text="change" />

    </androidx.appcompat.widget.LinearLayoutCompat>
</layout>

data class User(
    var name: ObservableField<String>,
    var age: ObservableField<Int>
)

mActivityBinding.user = User(ObservableField("ray"), ObservableField(21))是如何更新页面的?

实现此功能的核心逻辑类ActivityMainBindingImpl.java , 位于app/build/ap_generate_sources/debug/out/com.cnstrong.jetpackexercise.databinding目录下

   public class ActivityMainBindingImpl extends ActivityMainBinding  {
       ···
       ···
       public void setUser(@Nullable com.cnstrong.jetpackexercise.User User) {
        this.mUser = User;
        synchronized(this) {
            mDirtyFlags |= 0x4L;
        }
        notifyPropertyChanged(BR.user);
        super.requestRebind(); 
    }
       ····
       ····
   }

super.requestRebind() ->mUIThreadHandler.post(mRebindRunnable) -> executePendingBindings()-> executeBindingsInternal ->executeBindings ,方法调用链如上,最终调用ActivityMainBindingImpl的executeBindings()

  @Override
    protected void executeBindings() {
        long dirtyFlags = 0;
        synchronized(this) {
            dirtyFlags = mDirtyFlags;
            mDirtyFlags = 0;
        }
        java.lang.String javaLangStringNameUserName = null;
        androidx.databinding.ObservableField<java.lang.Integer> userAge = null; // 可关注属性
        com.cnstrong.jetpackexercise.User user = mUser; // user对象的mUser引用
        androidx.databinding.ObservableField<java.lang.String> userName = null;
        java.lang.String javaLangStringNameUserNameJavaLangStringTTTAgeUserAge = null;
        java.lang.String javaLangStringNameUserNameJavaLangStringTTTAge = null;
        java.lang.String userNameGet = null;
        java.lang.Integer userAgeGet = null;

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



                if (user != null) {
                    // read user.age
                    userAge = user.getAge();
                    // read user.name
                    userName = user.getName();
                }
                updateRegistration(0, userAge); // 给ObservableField属性注册监听,修改ObservableField的值会被监听到
                updateRegistration(1, userName);


                if (userAge != null) {
                    // read user.age.get()
                    userAgeGet = userAge.get();
                }
                if (userName != null) {
                    // read user.name.get()
                    userNameGet = userName.get();
                }


                // read ("name = ") + (user.name.get())
                javaLangStringNameUserName = ("name = ") + (userNameGet);

                // read (("name = ") + (user.name.get())) + ("\t\t\t age = ")
                javaLangStringNameUserNameJavaLangStringTTTAge = (javaLangStringNameUserName) + ("\t\t\t age = ");


                // read ((("name = ") + (user.name.get())) + ("\t\t\t age = ")) + (user.age.get())
                javaLangStringNameUserNameJavaLangStringTTTAgeUserAge = (javaLangStringNameUserNameJavaLangStringTTTAge) + (userAgeGet);
        }
        // batch finished
        if ((dirtyFlags & 0x17L) != 0) {
            // api target 1

            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView1, javaLangStringNameUserNameJavaLangStringTTTAgeUserAge); // 给textview设置text,TextViewBindingAdapter.setText方法
        }
        if ((dirtyFlags & 0x16L) != 0) {
            // api target 1

            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView2, userNameGet); // 给EditText设置text
        }
        if ((dirtyFlags & 0x10L) != 0) {
            // api target 1
                                                                // 给EditText设置TextWatcher,编辑EditText的值会被监听到
            androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.mboundView2,     (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, mboundView2androidTextAttrChanged);
        }
    }

先看一下setTextWatcher做了什么

@BindingAdapter(value = {"android:beforeTextChanged", "android:onTextChanged",
            "android:afterTextChanged", "android:textAttrChanged"}, requireAll = false)
    public static void setTextWatcher(TextView view, final BeforeTextChanged before,
            final OnTextChanged on, final AfterTextChanged after,
            final InverseBindingListener textAttrChanged) {
        final TextWatcher newValue;
        if (before == null && after == null && on == null && textAttrChanged == null) {
            newValue = null;
        } else {
            newValue = new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                    if (before != null) {
                        before.beforeTextChanged(s, start, count, after);
                    }
                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    if (on != null) {
                        on.onTextChanged(s, start, before, count);
                    }
                    if (textAttrChanged != null) {
                        textAttrChanged.onChange(); // EditText内容发生变化后,会回调textAttrChanged.onChange();
                    }
                }

                @Override
                public void afterTextChanged(Editable s) {
                    if (after != null) {
                        after.afterTextChanged(s);
                    }
                }
            };
        }
        final TextWatcher oldValue = ListenerUtil.trackListener(view, newValue, R.id.textWatcher);
        if (oldValue != null) {
            view.removeTextChangedListener(oldValue);
        }
        if (newValue != null) {
            view.addTextChangedListener(newValue);
        }
    }

编辑EditText,会调用mboundView2androidTextAttrChanged.onChange() , mboundView2androidTextAttrChanged 的代码如下

private androidx.databinding.InverseBindingListener mboundView2androidTextAttrChanged = new androidx.databinding.InverseBindingListener() {
        @Override
        public void onChange() {
            // Inverse of user.name.get()
            //         is user.name.set((java.lang.String) callbackArg_0)
            // mboundView2是EditText,getTextString(mboundView2)就是获取EditText的text内容
            java.lang.String callbackArg_0 = androidx.databinding.adapters.TextViewBindingAdapter.getTextString(mboundView2);
            // localize variables for thread safety
            // user.name
            androidx.databinding.ObservableField<java.lang.String> userName = null;
            // user.name != null
            boolean userNameJavaLangObjectNull = false;
            // user != null
            boolean userJavaLangObjectNull = false;
            // user
            com.cnstrong.jetpackexercise.User user = mUser;
            // user.name.get()
            java.lang.String userNameGet = null;



            userJavaLangObjectNull = (user) != (null);
            if (userJavaLangObjectNull) {


                userName = user.getName();

                userNameJavaLangObjectNull = (userName) != (null);
                if (userNameJavaLangObjectNull) {
                    // 双向绑定,这里把EditText的值给设置给了userName熟悉,完成 view - model的传值流程
                    userName.set(((java.lang.String) (callbackArg_0)));
                }
            }
        }
    };

也就是说,EditText的双向绑定是通过添加了TextWatcher完成的,其实像CheckBox的实现逻辑类似,差别是监听内容变化的方式不一样

可观测的数据修改时是如何更新UI的

在主线程里面调用user.name.set("carl")也会更新UI页面,这个过程是如何完成的呢?

看一下executeBindings()里面的updateRegistration(0, userAge)方法

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

CREATE_PROPERTY_LISTENER是一个常量

    private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
        @Override
        public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
            return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();
        }
    };

WeakPropertyListener.class如下

 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 void addListener(Observable target) {
            // 给Observable添加了一个OnPropertyChangedCallback,OnPropertyChangedCallback是this,也就是WeakPropertyListener对象自己
            // 后面发生回调的时候,会调用onPropertyChanged这个方法
            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);
        }
    }

WeakListener.class如下

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

        ····
        ····    
        //mObservable是WeakPropertyListener,mObservable.addListener(mTarget)给mTarget添加了一个OnPropertyChangedCallback对象 
        public void setTarget(T object) {
            unregister();
            mTarget = object;
            if (mTarget != null) {
                mObservable.addListener(mTarget);
            }
        }

        ····
        ····    

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

setTarget(T object)会给参数object添加一个OnPropertyChangedCallback回调,这里虽然是泛型,实际上object是Observable类型

接着看回updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER)

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

把保存WeakListener保存下来,然后注册

    /**
     * @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;
            if (mLifecycleOwner != null) {
                listener.setLifecycleOwner(mLifecycleOwner);
            }
        }
        // 给observable添加OnPropertyChangedCallback回调,OnPropertyChangedCallback回调会调用WeakPropertyListener的onPropertyChanged            方法
        listener.setTarget(observable); 
    }

observable参数值是userAge和userName,属于ObservableField

public class ObservableField<T> extends BaseObservableField implements Serializable {
    static final long serialVersionUID = 1L;
    private T mValue;
    ····
    ····
    ····    

    /**
     * @return the stored value.
     */
    @Nullable
    public T get() {
        return mValue;
    }

    /**
     * Set the stored value.
     *
     * @param value The new value
     */
    public void set(T value) {
        if (value != mValue) {
            mValue = value;
            notifyChange();
        }
    }
}

abstract class BaseObservableField extends BaseObservable {
  ····
  ····    
}

public class BaseObservable implements Observable {
    private transient PropertyChangeRegistry mCallbacks;

    // 注册OnPropertyChangedCallback回调
    @Override
    public void addOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {
        synchronized (this) {
            if (mCallbacks == null) {
                mCallbacks = new PropertyChangeRegistry();
            }
        }
        mCallbacks.add(callback);
    }
    ····
    ····    
}

DataBinding注册的OnPropertyChangedCallback被放到这个callbacks里面

给ObservableField赋值,实际是调用set方法

    public void set(T value) {
        if (value != mValue) {
            mValue = value;
            notifyChange(); // 触发监听者
        }
    }

    public void notifyChange() {
        synchronized (this) {
            if (mCallbacks == null) {
                return;
            }
        }
        mCallbacks.notifyCallbacks(this, 0, null);
    }

触发mCallbacks里面的OnPropertyChangedCallback,最终也就是回调WeakPropertyListener的onPropertyChanged方法,然后调用handleFieldChange

    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(); //刷新UI
        }
    }

思考

  • 对于非可观测的数据发生变化时,如何更新UI?

    可以手动调用:executePendingBindings()

  • 核心逻辑类ActivityMainBindingImpl.java是如何产生的

    APT原理

补充

LiveData双向绑定

与上面的一样,LiveData也有一个注册监听的过程

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

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

private static class LiveDataListener implements Observer,
            ObservableReference<LiveData<?>> {
        final WeakListener<LiveData<?>> mListener;// WeakListener实质是一个代理
        LifecycleOwner mLifecycleOwner;

        public LiveDataListener(ViewDataBinding binder, int localFieldId) {
            mListener = new WeakListener(binder, localFieldId, this);// WeakListener持有当前对象引用;
        }

        @Override
        public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
            LifecycleOwner owner = (LifecycleOwner) lifecycleOwner;
            LiveData<?> liveData = mListener.getTarget();
            if (liveData != null) {
                if (mLifecycleOwner != null) {
                    liveData.removeObserver(this);
                }
                if (lifecycleOwner != null) {
                    liveData.observe(owner, this);
                }
            }
            mLifecycleOwner = owner;
        }

        @Override
        public WeakListener<LiveData<?>> getListener() {
            return mListener;
        }

        @Override
        public void addListener(LiveData<?> target) {
            if (mLifecycleOwner != null) {
                target.observe(mLifecycleOwner, this);// addListener实质是给LiveData设置了观测者;
            }
        }

        @Override
        public void removeListener(LiveData<?> target) {
            target.removeObserver(this);
        }

        @Override
        public void onChanged(@Nullable Object o) {
            ViewDataBinding binder = mListener.getBinder();
            if (binder != null) {
                binder.handleFieldChange(mListener.mLocalFieldId, mListener.getTarget(), 0);
            }
        }
    }

实质与ObserverFiled的方式一样,区别在于_使用Livedata的时候要先给DataBinding设置一个LifecycleOwner_

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
img
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)

PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题

图片

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值