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

相关推荐
随遇丿而安2 小时前
第10周:Activity 基础功能与生命周期优化
android
alexhilton15 小时前
Android车载OS中的Remote Compose
android·kotlin·android jetpack
落魄Android在线炒饭1 天前
Android 自定义HAL开发篇之 HIDL篇——从入门到实战(上)
android
plainGeekDev1 天前
广播接收器 → Flow + Lifecycle
android·java·kotlin
plainGeekDev1 天前
EventBus → SharedFlow
android·java·kotlin
37手游移动客户端团队2 天前
招聘-高级安卓开发工程师
android·客户端
用户41659673693552 天前
WebView 请求异常排查操作手册
android·前端
Kapaseker2 天前
学不动了,入门 Compose Styles API
android·kotlin
墨狂之逸才3 天前
Android TV WebView 遥控器按键处理:从全透传到白名单
android
plainGeekDev3 天前
MVC 写法 → MVVM
android·java·kotlin