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

相关推荐
笔夏1 小时前
【安卓学习之FloatingActionButton】按钮太小
android·学习
XD7429716362 小时前
科技早报晚报|2026年5月15日:无摄像头空间感知、Android 设备实验室与视频检索代理,今天更值得跟进的 3 个技术机会
android·科技·音视频·开源项目·边缘ai·开发者工具
应用市场2 小时前
Android Verified Boot 2.0 安全启动原理详解
android·安全
只可远观2 小时前
Android XML命令式和Jetpack Compose声明式UI
android·xml
他是龙5512 小时前
DVWA 靶场深度解析:文件包含 & 文件上传(Low → Impossible)
android
_李小白2 小时前
【Android车载学习笔记】第一天:Android Automotive OS介绍
android·笔记
aqi003 小时前
FFmpeg开发笔记(一百零一)跨平台的开源音视频移动框架MobileFFmpeg
android·ffmpeg·音视频·直播·流媒体
2301_811130544 小时前
【保姆级教程】Android Studio完整安装步骤(2026最新版,新手零踩坑)
android·java
帅次4 小时前
Android 高级工程师面试参考答案:项目经历、自我介绍与实战案例表达
android·面试·职场和发展