一、Data Binding 是什么?
Data Binding(数据绑定) 是 Android 官方提供的一种库,用于将 UI 控件(如 TextView、ImageView)与数据源(如 Java/Kotlin 对象、LiveData)自动绑定。它通过声明式语法,直接在 XML 布局文件中定义数据与视图的关系,无需手动编写更新 UI 的代码,可以实现双向绑定。
二、为什么需要 Data Binding?
在传统 Android 开发中,开发者面临以下问题:
-
手动同步数据与 UI
-
每次数据变化时,需手动调用
findViewById
获取控件,再通过setText()
、setImage()
等方法更新 UI,代码冗余且易错。 -
示例痛点: // 传统方式更新UI user.name = "张三" textView.text = user.name // 手动同步
-
三、Data Binding 的核心解决方案
Data Binding 通过以下机制解决上述问题:
dataBinding {
enabled true
}
1. 声明式 XML 绑定
直接在布局文件中绑定数据,避免手动操作 UI:
<layout>
<data>
<variable name="user" type="com.example.User" />
</data>
<TextView
android:text="@{user.name}" /> <!-- 自动绑定数据 -->
</layout>
2. 自动更新 UI
当数据变化时,UI 自动刷新(需配合 Observable
对象或 LiveData
):
class User : BaseObservable() {
@Bindable
var name: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.name) // 通知UI更新
}
}
// 修改数据后,TextView 自动显示新值
user.name = "李四"
3. 支持复杂逻辑
在 XML 中直接编写表达式(如条件判断、方法调用):
<TextView
android:text="@{user.age > 18 ? '成年人' : '未成年人'}"
android:visibility="@{user.hasOrder ? View.VISIBLE : View.GONE}" />
4. 双向绑定
数据与 UI 可以双向同步(如输入框内容修改后自动更新数据模型):
<EditText
android:text="@={user.name}" /> <!-- @= 表示双向绑定 -->
三、源码分析
接下来,我们从DataBindingutil类的setcontentview开始看。
viewDataBindin = DataBindingUtil.setContentView(this, R.layout.xxx);
public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity,
int layoutId, @Nullable 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);
}
可以看到,里面立马就加载了我们的布局,然后添加到根布局里面,我们接着往下看。
会生成一个ViewDataBinding对象,
布局文件的里面的控件,就都会存放到我们的这个数组里面
这也是一个耗内存的地方。
我们还知道,双向绑定,那么必定会有监听布局改变,或者数据改变的地方。
对象创建以后,这里我们就会创建一个监听器出来监听。然后进行数据的绑定和ui的刷新
当有数据以后,我们就开始执行runnable的run方法
跳到这个方法,进行数据绑定和ui刷新。其实还是findViewById,然后使用settext等方法进行文本输入。只不过这些他们帮助我们完成了,如果不写绑定“@=或@”,那么就入下面一样,没有什么set。只不过是完成了findViewById
3.2 布局文件会被拆分成两个
- layout标签或data
- 可以绘制的
为什么要拆分呢?因为android绘制不认识这个layout标签,因为他既不是自定义的,没有全类名,也不是系统的,所以不认识。需要拆分出来进行绘制。