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

相关推荐
csj502 小时前
安卓基础之《(29)—消息机制与异步任务》
android
张风捷特烈2 小时前
状态管理大乱斗#02 | Bloc 源码全面评析
android·前端·flutter
untE EADO3 小时前
MySQL错误-this is incompatible with sql_mode=only_full_group_by完美解决方案
android·sql·mysql
诸神黄昏EX3 小时前
Android Google EDLA
android
常利兵3 小时前
从0到1,开启Android音视频开发之旅
android·音视频
2501_937145414 小时前
TV 影视大全:多品类聚合 稳定播放优化版
android·源码·源代码管理
followYouself4 小时前
Gradle、AGP、Plugin插件基本知识
android·gradle·plugin·agp
我命由我123454 小时前
Android 开发问题:Unresolved reference: kapt
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
黄昏晓x5 小时前
数据库 ---- 表的约束
android·数据库