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