Android-Kotlin基础(Jetpack②-Data Binding)
功能需求
显示用户的姓名、年龄、身份(学生 / 上班族)
点击按钮切换用户信息
一、传统方式实现
1. 布局文件(activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="16dp"><TextViewandroid:id="@+id/tvName"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="18sp"/><TextViewandroid:id="@+id/tvAge"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="8dp"/><TextViewandroid:id="@+id/tvIdentity"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="8dp"/><Buttonandroid:id="@+id/btnChange"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="切换用户"android:layout_marginTop="16dp"/></LinearLayout>
2. Activity 代码(MainActivity.kt)
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextViewclass MainActivity : AppCompatActivity() {// 声明所有需要操作的控件private lateinit var tvName: TextViewprivate lateinit var tvAge: TextViewprivate lateinit var tvIdentity: TextViewprivate lateinit var btnChange: Button// 数据private var currentUser = User("张三", 20, true)override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 1. 手动绑定所有控件(最繁琐的步骤)initViews()// 2. 手动更新UIupdateUI()// 3. 手动设置点击事件btnChange.setOnClickListener {// 切换数据currentUser = if (currentUser.name == "张三") {User("李四", 25, false)} else {User("张三", 20, true)}// 手动更新UIupdateUI()}}// 初始化所有控件(findViewById重复劳动)private fun initViews() {tvName = findViewById(R.id.tvName)tvAge = findViewById(R.id.tvAge)tvIdentity = findViewById(R.id.tvIdentity)btnChange = findViewById(R.id.btnChange)}// 手动更新所有控件内容private fun updateUI() {tvName.text = currentUser.nametvAge.text = "年龄:${currentUser.age}"tvIdentity.text = if (currentUser.isStudent) "学生" else "上班族"}// 数据类data class User(val name: String,val age: Int,val isStudent: Boolean)
}
二、Data Binding 方式实现
1. 布局文件(activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"><data><variablename="user"type="com.example.databindingdemo.MainActivity.User" /></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="16dp"><!-- 直接绑定数据,无需id --><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.name}" <!-- 数据绑定 -->android:textSize="18sp"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{`年龄:` + user.age}" <!-- 表达式拼接 -->android:layout_marginTop="8dp"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.isStudent ? `学生` : `上班族`}" <!-- 条件判断 -->android:layout_marginTop="8dp"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="切换用户"android:layout_marginTop="16dp"android:onClick="@{() -> user.change()}" <!-- 绑定点击事件 -->android:enabled="@{user.name.isNotEmpty()}"/> <!-- 动态控制启用状态 --></LinearLayout>
</layout>
2. Activity 代码(MainActivity.kt)
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.databindingdemo.databinding.ActivityMainBindingclass MainActivity : AppCompatActivity() {// 只需要声明Binding对象private lateinit var binding: ActivityMainBindingoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 初始化Binding(替代setContentView和findViewById)binding = ActivityMainBinding.inflate(layoutInflater)setContentView(binding.root)// 绑定数据(自动更新UI)binding.user = User("张三", 20, true)}// 数据类(包含修改逻辑)inner class User(val name: String,val age: Int,val isStudent: Boolean) {// 点击事件处理fun change() {// 直接修改绑定的数据,UI自动更新binding.user = if (name == "张三") {User("李四", 25, false)} else {User("张三", 20, true)}}}
}
三、核心差异对比
对比维度 | 传统方式 | Data Binding 方式 |
---|---|---|
控件获取 | 需手动写大量 findViewById | 自动生成 Binding 类,直接通过属性访问 |
UI 更新 | 需手动调用 setText() 等方法 | 数据变化后自动更新 UI |
代码量 | 多(初始化、更新逻辑重复) | 少(省略模板代码) |
可读性 | 数据与 UI 关联分散在代码中 | 数据与 UI 关联集中在布局中 |
维护成本 | 高(修改 UI 需同时改代码) | 低(布局与数据绑定一目了然) |
错误检查 | 运行时可能因控件 ID 错误崩溃 | 编译时检查绑定表达式,提前发现错误 |
事件处理 | 需手动设置 setOnClickListener | 布局中直接绑定事件,逻辑更集中 |
Data Binding 方式的区别
当使用 Data Binding 时,布局文件会被自动处理成一个 Binding 类(比如 activity_main.xml
会生成 ActivityMainBinding
类),这个类相当于布局文件的 "代码代表"。
第一行:binding = ActivityMainBinding.inflate(layoutInflater)
ActivityMainBinding
:自动生成的类,名字是布局文件名(下划线转驼峰)+ Bindinginflate(layoutInflater)
:这是解析布局的过程,相当于传统的 "把 XML 变成 View"- 执行后,
binding
对象就持有了整个布局的所有控件和数据绑定能力
第二行:setContentView(binding.root)
binding.root
:指的是布局文件的根节点(比如你布局中的LinearLayout
或ConstraintLayout
)- 这行代码的作用和传统
setContentView(R.layout.xxx)
一样:让 Activity 显示这个根节点对应的界面 - 区别是:传统方式直接传布局 ID,Data Binding 方式传已经解析好的根 View
形象比喻
可以把布局文件想象成 "设计图纸":
- 传统方式:直接告诉 Activity "用图纸 ID 302 建房子"(
setContentView(R.layout.xxx)
),之后需要自己去房子里找各个房间(findViewById
)。 - Data Binding 方式:先请一个 "施工队"(
ActivityMainBinding.inflate()
)根据图纸建好房子,得到一个 "房屋管理手册"(binding
),手册里记录了所有房间的位置。然后告诉 Activity "就用这个建好的房子"(setContentView(binding.root)
),之后想找哪个房间,直接查手册就行(binding.tvName
)。