DataBingding
博客创建时间:2021.04.12
博客更新时间:2021.04.13
以Android studio build=4.1.3,gradle=6.5,SdkVersion 30来分析讲解。如图文和网上其他资料不一致,可能是别的资料版本较低而已
在早期的DataBinding双向绑定中需要防止死循环造成ANR,解决方案是需要判断前后两次值变动的id值是否一样。但是在现在的高版本中该bug已在底层中结局,我们在文章后面会详细说明。
打开应用,登录页面会自动填充上次登录保存User的name 和password。
user.name="test"
user.password="123456"
binding.user=user
public class User {
// 用户名
public String name;
// 密码
public String password;
}
如果此时想换一个用户登陆,常规方法是Edittext.getText获得name和password,然后进行登陆操作
现在使用双向绑定。
<EditText
android:id="@+id/etName"
android:text="@={user.name}"
android:inputType="text" />
<EditText
android:id="@+id/etPassword"
android:text="@={user.password}"/>
@={}
就是双向绑定符
现在只要我们对name和password EditText输入内容进行改变分别为“admin”和“987654321”,那么user中对应的两个字段的值就会自动变动。
进行登陆操作时依然只用拿user来用就可以了。点击登陆按钮测试值
else if(v?.id ==R.id.btnLogin){
Log.i("1111","name="+user.name+" password="+user.password)
}
// 输出
name=admin password=987654321
每个Fragment或Activity的布局开启DataBinding后都会生成一个ViewDataBinding子类。我们来分析其中关键源码
1. ActivityMainBinding 的初始化
ActivityMainBinding进行相关初始化设置,绑定数据与DataBinding的关联
private ActivityMainBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] bindings) {
//1. ActivityMainBinding 布局界面初始化,包括相关的值赋予
invalidateAll();
}
/**
* 初始化布局,并对控件的设值赋值
*/
@Override
public void invalidateAll() {
synchronized(this) {
mDirtyFlags = 0x10L;
}
// 请求重新绑定,主要是对控件的各值显示进行变动
requestRebind();
}
2. 指定变量赋值
public void setLiveData(@Nullable com.xuanyuan.databindinganalysis.MyObservableField LiveData) {
updateRegistration(0, LiveData);
this.mLiveData = LiveData;
synchronized(this) {
mDirtyFlags |= 0x1L;
}
notifyPropertyChanged(BR.liveData);
super.requestRebind();
}
public void setClick(@Nullable android.view.View.OnClickListener Click) {
this.mClick = Click;
synchronized(this) {
mDirtyFlags |= 0x4L;
}
notifyPropertyChanged(BR.click);
super.requestRebind();
}
3. 通知更新指定变量
// 控件的各值进行确定赋予
@Override
public boolean setVariable(int variableId, @Nullable Object variable) {
boolean variableSet = true;
else if (BR.liveData == variableId) {
setLiveData((com.xuanyuan.databindinganalysis.MyObservableField) variable);
} else {
variableSet = false;
}
return variableSet;
}
4. 变量Change,通知UI刷新
@Override
protected void executeBindings() {
...
if ((dirtyFlags & 0x11L) != 0) {
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.etName, liveDataGet);
}
if ((dirtyFlags & 0x10L) != 0) {
// api target 1
androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.etName, null,null, etNameandroidTextAttrChanged);
}
}
当我们使用"@={}"双向绑定符时,观测ViewBindingIml代码。
1.常规双向绑定
private androidx.databinding.InverseBindingListener etNameandroidTextAttrChanged = new androidx.databinding.InverseBindingListener() {
@Override
public void onChange() {
java.lang.String callbackArg_0 = androidx.databinding.adapters.TextViewBindingAdapter.getTextString(etName);
java.lang.String userName = null;
boolean userJavaLangObjectNull = false;
com.xuanyuan.databindinganalysis.User user = mUser;
userJavaLangObjectNull = (user) != (null);
if (userJavaLangObjectNull) {
user.setName(((java.lang.String) (callbackArg_0)));
}
}
};
TextViewBindingAdapter.setTextWatcher(this.etName, null, null, null, etNameandroidTextAttrChanged);
其实这种双向绑定只是调用了 view.addTextChangedListener(newValue),对内容变动后的监听操作处理,源码中自动帮我们处理了。
2. Observable双向绑定
val livaValue = MyObservableField()
override fun onClick(v: View?) {
if (v?.id == R.id.btnLogin) {
val value = Math.random() * 1300
livaValue.set(value.toString())
}
}
<EditText
android:id="@+id/etName"
android:layout_width="match_parent"
android:text="@={liveData}"
android:inputType="text" />
当调用livaValue.set()时,阅读源码会发现有更新回调,最终执行ViewBinding的executeBindings()方法
@Override
protected void executeBindings() {
...
}
更新调用后,EditText中的值变化,会触发TextChangedListener再次调用livaValue.set(value.toString()。此时EditText中的值变化中的值不再变化
本文主要讲解了双向绑定的意义,如何使用双向绑定。
对于DataBinding的分析需要查看对应ViewDataBinding类,即可透过现象看本质。
本测试Demo源码
gitee:https://gitee.com/luofaxin/RxJava3Analysis.git
github:https://github.com/l424533553/RxJava3Analysis.git
相关链接:
扩展链接:
扩展训练:
博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收藏 ^ _ ^ !