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

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

相关推荐
冉冉同学2 小时前
AI Agent 开始操作真实手机:移动端自动化的 3 个新考点
android·ai编程
帅得不敢出门3 小时前
Android Framework关闭软件低电关机功能测试PMIC低电保护
android
熊猫钓鱼>_>3 小时前
Kotlin Multiplatform for OpenHarmony 实战:为 Landscapist 实现图片加载适配
开发语言·kotlin·华为云·ai编程·harmonyos·鸿蒙·openharmony
恋猫de小郭4 小时前
Flutter + EmbeddingGemma 2,谷歌发布完全端侧的 AI Edge Foresight
android·前端·flutter
ZealSinger4 小时前
Kotlin2.4迁移context parameters
kotlin·协程·迁移·kotlin2.4
墨天梦5 小时前
B16_Material主题与可访问交互
android·kotlin·交互
弯_弯5 小时前
企业知识库 RAG 落地:从 Demo 到生产,四条工程链路与参数级自查
android·java·javascript
晚风叙码7 小时前
MySQL 表的约束详解:从空属性到外键
android·数据库·mysql·adb
alexhilton17 小时前
模块化Jetpack Compose架构
android·kotlin·android jetpack
厮年断弦19 小时前
AI 辅助开发实录:一周做完一个 Android 本地音乐播放器,这些坑替你踩了
android