Android DataBinding数据绑定表达式、双向绑定

9.3 数据绑定表达式

9.3.1 基本表达式

常用表达式类型

表达式类型 示例 说明
属性访问 @{user.name} 访问对象的属性
方法调用 @{user.getName()} 调用对象的方法
字符串格式化 @{@string/name_format(user.name)} 使用字符串资源
算术运算 @{user.age + 1} 算术运算
逻辑运算 @{user.isAdult && user.hasPermission} 逻辑运算
三元运算符 @{user.isAdult ? '成年' : '未成年'} 条件判断
空合并 @{user.nickName ?? user.name} 空值合并
集合访问 @{user.addresses[0]} 访问集合元素

表达式示例

xml 复制代码
<data>
    <variable
        name="user"
        type="com.example.app.model.User" />
</data>

<!-- 属性访问 -->
<TextView
    android:text="@{user.name}" />

<!-- 方法调用 -->
<TextView
    android:text="@{user.getFullName()}" />

<!-- 字符串格式化 -->
<TextView
    android:text="@{@string/user_info(user.name, user.age)}" />

<!-- 算术运算 -->
<TextView
    android:text="@{@string/age_plus_one(user.age + 1)}" />

<!-- 逻辑运算 -->
<TextView
    android:visibility="@{user.isAdult && user.hasPermission ? View.VISIBLE : View.GONE}" />

<!-- 三元运算符 -->
<TextView
    android:text="@{user.isAdult ? '成年' : '未成年'}" />

<!-- 空合并 -->
<TextView
    android:text="@{user.nickName ?? user.name}" />

<!-- 集合访问 -->
<TextView
    android:text="@{user.addresses[0].city}" />

9.3.2 字符串资源引用

strings.xml

xml 复制代码
<resources>
    <string name="name_format">姓名:%s</string>
    <string name="age_format">年龄:%d</string>
    <string name="user_info">%s,%d 岁</string>
</resources>

在布局中使用

xml 复制代码
<TextView
    android:text="@{@string/name_format(user.name)}" />

<TextView
    android:text="@{@string/age_format(user.age)}" />

<TextView
    android:text="@{@string/user_info(user.name, user.age)}" />

9.3.3 Import 语句

Import 类

xml 复制代码
<data>
    <import type="android.view.View" />
    <import type="android.text.TextUtils" />
    <import type="com.example.app.utils.StringUtils" />
    <import type="com.example.app.model.User" alias="UserModel" />
    <variable
        name="user"
        type="UserModel" />
</data>

<!-- 使用导入的类 -->
<TextView
    android:visibility="@{TextUtils.isEmpty(user.name) ? View.GONE : View.VISIBLE}" />

<TextView
    android:text="@{StringUtils.formatUser(user)}" />

9.4 双向数据绑定

9.4.1 双向绑定的概念

单向绑定 vs 双向绑定

类型 数据流向 说明
单向绑定 数据 → UI 数据变化自动更新 UI
双向绑定 数据 ↔ UI 数据变化更新 UI,UI 变化也更新数据

9.4.2 实现双向绑定

方式1:使用 Observable Field

kotlin 复制代码
/**
 * 用户模型
 */
class User : BaseObservable() {
    
    @get:Bindable
    var name: String = ""
        set(value) {
            field = value
            notifyPropertyChanged(BR.name)
        }
    
    @get:Bindable
    var age: Int = 0
        set(value) {
            field = value
            notifyPropertyChanged(BR.age)
        }
    
    @get:Bindable
    var email: String = ""
        set(value) {
            field = value
            notifyPropertyChanged(BR.email)
        }
}
xml 复制代码
<data>
    <variable
        name="user"
        type="com.example.app.model.User" />
</data>

<!-- 双向绑定 -->
<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={user.name}"
    android:hint="姓名" />

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={user.age}"
    android:hint="年龄"
    android:inputType="number" />

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={user.email}"
    android:hint="邮箱"
    android:inputType="textEmailAddress" />

方式2:使用 ObservableField

kotlin 复制代码
/**
 * 用户模型
 */
class User {
    val name = ObservableField<String>()
    val age = ObservableField<Int>()
    val email = ObservableField<String>()
}
kotlin 复制代码
/**
 * 用户 Activity
 */
class UserActivity : AppCompatActivity() {
    
    private lateinit var binding: ActivityUserBinding
    private lateinit var user: User
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        binding = DataBindingUtil.setContentView(this, R.layout.activity_user)
        
        // 创建 User 对象
        user = User()
        user.name.set("张三")
        user.age.set(25)
        user.email.set("zhangsan@example.com")
        
        // 设置数据到绑定对象
        binding.user = user
        binding.lifecycleOwner = this
    }
}

方式3:使用 MutableLiveData

kotlin 复制代码
/**
 * 用户 ViewModel
 */
class UserViewModel : ViewModel() {
    
    private val _user = MutableLiveData<User>()
    val user: LiveData<User> = _user
    
    private val _name = MutableLiveData<String>()
    val name: LiveData<String> = _name
    
    private val _age = MutableLiveData<Int>()
    val age: LiveData<Int> = _age
    
    private val _email = MutableLiveData<String>()
    val email: LiveData<String> = _email
    
    fun loadUser(userId: String) {
        viewModelScope.launch {
            val user = userRepository.getUser(userId)
            _user.value = user
            _name.value = user.name
            _age.value = user.age
            _email.value = user.email
        }
    }
    
    fun updateUser() {
        viewModelScope.launch {
            val user = User(
                name = _name.value ?: "",
                age = _age.value ?: 0,
                email = _email.value ?: ""
            )
            userRepository.updateUser(user)
        }
    }
}
xml 复制代码
<data>
    <variable
        name="viewModel"
        type="com.example.app.viewmodel.UserViewModel" />
</data>

<!-- 双向绑定 -->
<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={viewModel.name}"
    android:hint="姓名" />

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={viewModel.age}"
    android:hint="年龄"
    android:inputType="number" />

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={viewModel.email}"
    android:hint="邮箱"
    android:inputType="textEmailAddress" />

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="更新"
    android:onClick="@{() -> viewModel.updateUser()}" />

主要是databinding的表达式和双向绑定(EditText)。

相关推荐
达达尼昂16 小时前
在 Claude Cowork 中用好 Claude Fable 5
android·人工智能·后端
sTone8737517 小时前
写时复制COW的第一性理解
android·c++·flutter
sTone8737517 小时前
Zygote的第一性理解
android
sTone8737517 小时前
类RN框架通过Service暴露卡片渲染能力给AI Chat
android·react native
灯火不休17 小时前
Android Studio & Flutter 构建命令完全指南
android
杉氧17 小时前
Ktor 全栈之路 (5):JWT 认证全流程实战 —— 打造安全通信闭环
android·架构·kotlin
️学习的小王17 小时前
Python + MySQL 学生信息管理系统实战教程
android·python·mysql
帅次17 小时前
Android 高级工程师面试:Flutter 路由导航 近1年高频追问 18 题
android·flutter·面试
alexhilton1 天前
MVI模式的完整历史、误解和现代Android范式
android·kotlin·android jetpack
心中有国也有家1 天前
AtomGit Flutter 鸿蒙客户端:Canvas 绘制进阶-路径、渐变与混合模式
android·javascript·flutter·华为·harmonyos