RecyclerView(6) 搭配使用 DataBinding
目的是:设置数据绑定,并消除对 findViewById() 的调用
和前面系列文章一样, 关注 DataBinding /BindingAdapter 在RecyclerView 上的使用思想, 忽略具体的代码细节.
1.向布局文件 添加 数据绑定
(1)在 Code 标签页中打开 list_item_sleep_night.xml 布局文件。
将光标放在 ConstraintLayout 标签上,然后按 Alt+Enter
系统随即会打开 intent 菜单(“quick fix”菜单)。
(2)选择 Convert to data binding layout。这会将布局封装到 <layout> 中,并在其中添加 <data> 标签。
(3)根据需要滚动回顶部,并在 <data> 标签内声明一个名为 sleep 的变量。
(4)将其 type 设为 SleepNight 的完全限定名称
com.example.android.trackmysleepquality.database.SleepNight。
完成后的 <data> 标签应如下所示:
<layout
<data>
<variable
name="sleep"
type="com.example.android.trackmysleepquality.database.SleepNight"/>
</data>
</layout>
可见,加了一层 父布局 <layout>
(5) 如需强制创建 Binding 对象,请依次选择 Build > Clean Project,
然后依次选择 Build > Rebuild Project。
(如果仍然存在问题,请依次选择 File > Invalidate Caches / Restart。)
ListItemSleepNightBinding 绑定对象以及相关代码会添加到项目生成的文件中。
2. 第 2 步:使用 数据绑定 加载 项布局
SleepNightAdapter 的ViewHolder 中,
删除:
val view = layoutInflater
.inflate(R.layout.list_item_sleep_night, parent, false)
增加:
val binding =
ListItemSleepNightBinding.inflate(layoutInflater, parent, false)
修改:
return ViewHolder(binding) // 参数为 ListItemSleepNightBinding
//参数为 ListItemSleepNightBinding 且 binding.root 为根View (例子中的ConstraintLayout)
lass ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root){
此外, ViewHolder 中的自定的变量也可删掉,使用binding.xxx.
至此, 使用了DataBinding 取代了 findViewById 的操作,
通过 布局对应的 Binding 类, 直接获取到 控件.
例如:
android:id="@+id/quality_string" ====> binding.qualityString
注意: 会把下划线去掉, 变成驼峰式变量名
3. 创建 绑定适配器 BindingAdapter
绑定适配器 会获取数据特别是复杂的,
并将其调整为可供数据绑定功能用于绑定视图(例如文本或图片)的内容
实现三个绑定适配器,一个用于高质量图片,另外两个分别用于一个文本字段
要定义一种获取项和视图的方法,并用 @BindingAdapter 进行注解
在 Kotlin 中,可以在接收数据的视图类上将 绑定适配器编写为 扩展函数
3.1 创建 BindingAdapter 声明的函数
其实这里就是为了 将 SleepNight 数据, 转换成 能够在 View 上显示的数据(文本、图片)
创建 BindingUtils.kt, 用于创建 静态函数
class BindingUtils {}
(1) 睡眠时间 sleepDurationFormatted
在 TextView 上声明一个名为 setSleepDurationFormatted 的扩展函数
将数据绑定到视图,如在 ViewHolder.bind() 中一样.
请使用 @BindingAdapter 为该函数添加注解, 向数据绑定功能告知此绑定适配器.
@BindingAdapter("sleepDurationFormatted")
fun TextView.setSleepDurationFormatted(item: SleepNight) {
text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, context.resources)
}
(2) 睡眠质量 sleepQualityString
@BindingAdapter("sleepQualityString")
fun TextView.setSleepQualityString(item: SleepNight) {
text = convertNumericQualityToString(item.sleepQuality, context.resources)
}
(3)sleepImage
@BindingAdapter("sleepImage")
fun ImageView.setSleepImage(item: SleepNight) {
setImageResource(when (item.sleepQuality) {
0 -> R.drawable.ic_sleep_0
1 -> R.drawable.ic_sleep_1
2 -> R.drawable.ic_sleep_2
3 -> R.drawable.ic_sleep_3
4 -> R.drawable.ic_sleep_4
5 -> R.drawable.ic_sleep_5
else -> R.drawable.ic_sleep_active
})
}
这个相对简单了.
3.2 在ViewHolder 中为 布局文件 设置 数据类对象.
class ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(
item: SleepNight
) {
binding.sleep = item
// 此调用是一种优化,用于要求数据绑定功能立即执行任何待处理的绑定
// 当您在 RecyclerView 中使用绑定适配器时,最好调用 executePendingBindings(),因为它可以略微加快调整视图大小的过程
binding.executePendingBindings()
/* // 可以使用 Databinding 和 BindingAdapter 执行
val res = itemView.context.resources
binding.sleepLength //取代 viewHolder.findViewById(R.id.sleep_length)
.text = convertDurationToFormatted(
item.startTimeMilli, item.endTimeMilli, res
)
binding.qualityString.text = convertNumericQualityToString(item.sleepQuality, res)
binding.qualityImage.setImageResource(
when (item.sleepQuality) {
0 -> R.drawable.ic_sleep_0
1 -> R.drawable.ic_sleep_1
2 -> R.drawable.ic_sleep_2
3 -> R.drawable.ic_sleep_3
4 -> R.drawable.ic_sleep_4
5 -> R.drawable.ic_sleep_5
else -> R.drawable.ic_sleep_active
}
)
*/
}
注意: 需要在 类的顶级, 即在类体外部
3.3 向 XML 布局添加绑定
为文本、图片View 添加 绑定 (数据类)
因为 3.1 中创建的 BindingAdapter 函数 都需要一个参数 SleepNight(这里是sleep对象)
app:sleepImage="@{sleep}"
app:sleepDurationFormatted="@{sleep}"
app:sleepQualityString="@{sleep}"
至此,已完成所有.
参考文献:
https://developer.android.com/codelabs/kotlin-android-training-diffutil-databinding?hl=zh-cn#6
完整代码:
https://github.com/google-developer-training/android-kotlin-fundamentals-apps/tree/master/RecyclerViewDiffUtilDataBinding