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

相关推荐
哆啦A梦z7 分钟前
Android BLE 实战:从小米手环 7 踩坑到完整连接框架
android
笑一下蒜了.44 分钟前
Linux 存储多路径访问手册|multipath.conf 各配置段详解
android·linux·运维
凡泰AI1 小时前
如何通过小程序多端框架,让一个小程序同时运行在iOS、安卓、鸿蒙以及PC客户端,实现一次开发多端运行的效果
android·ios·小程序
一笑的小酒馆2 小时前
Androidiot扫地机器人设备详情页地图加载慢卡顿优化方案
android
xixiaoyunya2 小时前
安卓远程管理电脑/NAS文件:从传统SMB方案到Web化私有云的选型与落地实践
android·电脑
Zhu7587 小时前
在k8s集群部署MySQL单实例,支持多个主流发行版
android·mysql·kubernetes
AFinalStone10 小时前
Android 7系统异常问题排查(四)Framework层(上)—System Server Watchdog
android·系统异常
宝杰X712 小时前
Android Room3 多平台数据库
android·数据库
huibin14785236915 小时前
热缓解学习记录
android·学习
我命由我1234518 小时前
匈牙利命名法
java·服务器·后端·学习·java-ee·kotlin·学习方法