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开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)