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)
    }
}

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

相关推荐
2501_915909063 小时前
全面解析iOS应用上架到App Store的完整流程与关键注意事项
android·macos·ios·小程序·uni-app·cocoa·iphone
淡淡的香烟5 小时前
AndroidAI使用心得
android
chjif6 小时前
Android 设备管控开发实战:无障碍如何准确识别当前前台 App?
android
chjif6 小时前
Android 设备管控开发实战:企业受控终端的 DNS 域名策略实现
android·华为·harmonyos
c238567 小时前
MySQL 基础用法(下):查询进阶与核心特性
android·c语言·c++·mysql
math_hongfan8 小时前
鸿蒙Agent高级技能自定义开发:自定义意图服务/能力注册/Agent技能编排/服务插件开发实战
android·学习·华为·harmonyos·鸿蒙
2501_915106329 小时前
iOS 证书类型及作用说明 账号证书与签名配置的完整解读
android·ios·小程序·https·uni-app·iphone·webview
九皇叔叔9 小时前
RHEL9 安装 MySQL 8.4.11.LTS 版本
android·mysql·adb
海兰9 小时前
【数据库】tdsql(MySQL )的事务隔离级别
android·数据库·mysql
哆啦A梦z9 小时前
Android BLE 实战:从小米手环 7 踩坑到完整连接框架
android