📚 Data Binding: <include> 传递 ViewModel 笔记
核心原理
在 Android Data Binding 中,ViewModel 的传递是通过 <include> 标签上的 bind: 属性实现的一种显式赋值机制。
- 父布局中声明的变量不会自动传递给子布局。
- 要传递,必须在
<include>标签中指明:bind:【子布局变量名】="@{【父布局变量实例】}"。 ViewModel的生命周期和响应式更新(ObservableField/LiveData)由父布局设置的lifecycleOwner统一管理。- MVVM中的<include>布局复用:viewModel传递 - 简书
1. ViewModel (数据源)
假设我们需要一个包含布尔状态的 ViewModel。
// MyComponentViewModel.kt
import androidx.lifecycle.ViewModel
import androidx.databinding.ObservableField
class MyComponentViewModel : ViewModel() {
// 示例:需要被子布局观察和操作的状态
val isToggled = ObservableField(false)
fun toggle() {
isToggled.set(!isToggled.get())
}
}
2. 子布局 (layout_reusable_component.xml)
子布局必须使用 <data> 块声明一个 <variable> 作为接口来接收 ViewModel。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="componentVm"
type="com.example.viewmodel.MyComponentViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{componentVm.isToggled ? `状态: ON` : `状态: OFF`}"
android:onClick="@{() -> componentVm.toggle()}" />
</LinearLayout>
</layout>
3. 父布局 (activity_main.xml)
父布局必须持有 ViewModel 实例,并在 <include> 标签上进行显式绑定。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="mainVm"
type="com.example.viewmodel.MyComponentViewModel" />
</data>
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`全局状态: ` + mainVm.isToggled}" />
<include
android:id="@+id/included_component"
layout="@layout/layout_reusable_component"
bind:componentVm="@{mainVm}" />
</LinearLayout>
</layout>
4. Activity/Fragment (Kotlin 代码)
Activity/Fragment 只需要完成主布局的绑定。
// MainActivity.kt
class MainActivity : AppCompatActivity() {
// 实例化 ViewModel
private val myViewModel: MyComponentViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.apply {
// 步骤 4: 为主 Binding 设置 ViewModel 实例
this.mainVm = myViewModel
// 步骤 5: 设置 lifecycleOwner,确保数据响应式更新向下传递
lifecycleOwner = this@MainActivity
}
}
}
5. 关键点总结
| 检查项 | 说明 | 强制要求 |
|---|---|---|
| 子布局变量 | 必须在 <data> 中声明 <variable> 来接收参数。 |
必须存在 |
bind: 属性 |
在 <include> 上使用 bind:子变量名="@{父实例}" 进行传递。 |
必须使用 bind: 前缀 |
| 变量名匹配 | bind:componentVm 必须与子布局中的 name="componentVm" 一致。 |
名称必须匹配 |
lifecycleOwner |
必须在 Activity/Fragment 中设置 binding.lifecycleOwner = this。 |