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

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

相关推荐
_祝你今天愉快1 小时前
Android Binder 驱动 - 内核驱动层源码初探
android
stevenzqzq1 小时前
【无标题】
android
梦幻通灵2 小时前
Notepad++格式化Json两种方案【持续更新】
android·json·notepad++
1024+3 小时前
YOLO 转 RKNN 识别率降低调优操作手册(新手篇)
android·yolo·kotlin
木易 士心4 小时前
深度解析 Android 音频焦点处理与实战开发
android·音视频
祉猷并茂,雯华若锦5 小时前
Appium 3.x安卓APP企业级安装实战
android·appium
微露清风6 小时前
浅析 MySQL 索引
android·数据库·mysql
91刘仁德6 小时前
MySQL 数据类型详解
android·笔记·mysql·adb
编程圈子7 小时前
操作系统学习14 IDT + PIC + 键盘中断
android·学习·计算机外设
齊家治國平天下14 小时前
Android 14 Vehicle HAL (VHAL) 设计与实现深度解析
android·aaos·carservice·车载开发·android 14·vhal·vehicle hal