Adroid Data Binding数据绑定对比(findViewXX、ButterKnife)

9.1 数据绑定基础对比

kotlin 复制代码
// 传统方式 - findViewById
class UserActivity : AppCompatActivity() {
    private lateinit var tvName: TextView
    private lateinit var tvAge: TextView
    private lateinit var tvEmail: TextView
    private lateinit var tvPhone: TextView
    private lateinit var tvAddress: TextView
    private lateinit var btnUpdate: Button
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_user)
        
        // 大量的 findViewById 调用
        tvName = findViewById(R.id.tvName)
        tvAge = findViewById(R.id.tvAge)
        tvEmail = findViewById(R.id.tvEmail)
        tvPhone = findViewById(R.id.tvPhone)
        tvAddress = findViewById(R.id.tvAddress)
        btnUpdate = findViewById(R.id.btnUpdate)
        
        // 加载用户数据
        loadUserData()
    }
    
    private fun loadUserData() {
        val user = userRepository.getUser("123")
        // 手动更新每个 View
        tvName.text = user.name
        tvAge.text = user.age.toString()
        tvEmail.text = user.email
        tvPhone.text = user.phone
        tvAddress.text = user.address
    }
    
    private fun updateUser(user: User) {
        // 手动更新每个 View
        tvName.text = user.name
        tvAge.text = user.age.toString()
        tvEmail.text = user.email
        tvPhone.text = user.phone
        tvAddress.text = user.address
    }
}



    // ===================== 1. ButterKnife 绑定控件 =====================
    @BindView(R.id.tv_name)  // 对应布局 TextView id
    TextView tvName;

    @BindView(R.id.tv_age)
    TextView tvAge;
java 复制代码
//  - ButterKnife
    @BindView(R.id.tv_name)  // 对应布局 TextView id
    TextView tvName;

    @BindView(R.id.tv_age)
    TextView tvAge;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 1. 初始化 ButterKnife
        ButterKnife.bind(this);
    
        // 3. 直接赋值!
        setDataToView();
    }

传统方式的问题

问题 说明 影响
样板代码 大量的 findViewById 调用 代码冗余,难以维护
手动更新 需要手动更新每个 View 容易遗漏,容易出错
可读性差 UI 逻辑与业务逻辑混合 代码可读性差
类型不安全 使用字符串 ID 获取 View 运行时错误
难以测试 UI 逻辑与业务逻辑耦合 难以单元测试
kotlin 复制代码
// 使用 Data Binding
class UserActivity : AppCompatActivity() {
    
    private lateinit var binding: ActivityUserBinding
    private lateinit var viewModel: UserViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 设置绑定
        binding = DataBindingUtil.setContentView(this, R.layout.activity_user)
        viewModel = ViewModelProvider(this).get(UserViewModel::class.java)
        
        // 设置数据
        binding.viewModel = viewModel
        binding.lifecycleOwner = this
        
        // 数据更新会自动反映到 UI 在xml布局文件中使用User
        viewModel.loadUser("123")
    }
}

Data Binding 的优势

优势 说明
消除样板代码 自动生成 View 的引用,无需 findViewById
自动 UI 更新 数据变化自动反映到 UI
类型安全 编译时检查,避免运行时错误
代码简洁 UI 逻辑与业务逻辑分离
易于测试 UI 逻辑可以独立测试

9.2 Data Binding 快速入门

9.2.1 启用 Data Binding

在 build.gradle 中启用

gradle 复制代码
android {
    // ...
    dataBinding {
        enabled = true
    }
}

9.2.2 创建布局文件

布局文件结构

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.example.app.model.User" />
        <variable
            name="viewModel"
            type="com.example.app.viewmodel.UserViewModel" />
        
        <import type="android.view.View" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".ui.user.UserActivity">
        <!-- 用户名 -->
        <TextView
            android:id="@+id/tvName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name}"
            android:textSize="20sp"
            android:textStyle="bold"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginTop="50dp" />
        <!-- 年龄 -->
        <TextView
            android:id="@+id/tvAge"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{@string/age_format(user.age)}"
            android:textSize="16sp"
            app:layout_constraintTop_toBottomOf="@id/tvName"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginTop="20dp" />
        <!-- 邮箱 -->
        <TextView
            android:id="@+id/tvEmail"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.email}"
            android:textSize="16sp"
            app:layout_constraintTop_toBottomOf="@id/tvAge"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginTop="20dp" />
        <!-- 电话 -->
        <TextView
            android:id="@+id/tvPhone"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.phone}"
            android:textSize="16sp"
            app:layout_constraintTop_toBottomOf="@id/tvEmail"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginTop="20dp" />

        <!-- 地址 -->
        <TextView
            android:id="@+id/tvAddress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.address}"
            android:textSize="16sp"
            app:layout_constraintTop_toBottomOf="@id/tvPhone"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginTop="20dp" />

        <!-- 更新按钮 -->
        <Button
            android:id="@+id/btnUpdate"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="更新"
            android:onClick="@{() -> viewModel.updateUser()}"
            android:visibility="@{viewModel.isLoading ? View.GONE : View.VISIBLE}"
            app:layout_constraintTop_toBottomOf="@id/tvAddress"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginTop="30dp" />

        <!-- 加载进度条 -->
        <ProgressBar
            android:id="@+id/progressBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="@{viewModel.isLoading ? View.VISIBLE : View.GONE}"
            app:layout_constraintTop_toBottomOf="@id/tvAddress"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginTop="30dp" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

9.2.3 在 Activity 中使用 Data Binding

kotlin 复制代码
/**
 * 用户 Activity
 */
class UserActivity : AppCompatActivity() {
    
    private lateinit var binding: ActivityUserBinding
    private lateinit var viewModel: UserViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // 使用 DataBindingUtil.setContentView 代替 setContentView
        binding = DataBindingUtil.setContentView(this, R.layout.activity_user)
        viewModel = ViewModelProvider(this).get(UserViewModel::class.java)
        
        // 设置数据到绑定对象
        binding.viewModel = viewModel
        binding.lifecycleOwner = this
        
        // 加载用户数据
        val userId = intent.getStringExtra("USER_ID") ?: ""
        viewModel.loadUser(userId)
    }
}

以上是对比以及快速入门参考案例。

相关推荐
修炼者4 小时前
Gradle三阶段
android
morchalen4 小时前
安卓framework学习6:Contacts 联系人 APP 日志
android
KANGBboy4 小时前
java知识四(面向对象编程)
android·java·开发语言
AD钙奶-lalala8 小时前
Android Studio新建项目默认不使用Compose模版
android·ide·android studio
故渊at10 小时前
第一板块:Android 系统基石与运行原理 | 第二篇:Android 编译、打包与安装机制
android·系统架构·apk·打包·application·dalvik·android编译
故渊at10 小时前
第一板块:Android 系统基石与运行原理 | 第三篇:ART 与 Dalvik 运行时环境原理
android·对象模型·内存布局·运行原理·art·dalvik
私人珍藏库11 小时前
【Android】Wallcraft 3.62.0-最强4 K壁纸软件-解锁高级版
android·智能手机·app·工具·软件·多功能
GesLuck12 小时前
Node-RED企业微信发送—群文件
android·java·企业微信
whatever who cares12 小时前
android中fragment demo举例
android·java·开发语言
zhangphil12 小时前
Android将ImageView显示的图原样取出转换为Bitmap,Kotlin
android·kotlin