简介
实现数据的双向绑定,接收数据的更改同时监听用户对数据的更新
集成
参照官网DataBinding集成
使用
- 第一步
创建数据模型class DataBindingMode{ var name = "p" var sex = 0 var birth = "" }
- 第二步
创建布局文件,使用DataBinding,布局顶层需要使用layout。<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <data> <import type="com.pds.jetpack.utils.TimeUtils"/> <variable name="clickListener" type="android.view.View.OnClickListener"/> <variable name="dataBindingMode" type="com.pds.jetpack.databinding.DataBindingMode"/> </data> <LinearLayout ... tools:context=".databinding.DataBindingActivity"> <TextView android:id="@+id/name" ... android:text="@{dataBindingMode.name + TimeUtils.getAge(dataBindingMode.birth)}" /> <include layout="@layout/contact" bind:dataMode="@{dataBindingMode}"/> </LinearLayout> </layout>
- 第三步
初始化数据,实现数据更新,如果没有找到对应的DataBinding生成类,者先编译一下工程。override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 以前的setContentView方法改为调用DataBindingUtil的setContentView方法 val binding: ActivityDataBindingBinding = DataBindingUtil.setContentView(this,R.layout.activity_data_binding) // 绑定数据 val dataBindingMode = DataBindingMode() dataBindingMode.name = "pds" dataBindingMode.birth = "1993-06-17" dataBindingMode.sex = 1 binding.dataBindingMode = dataBindingMode }
binding.dataBindingMode = dataBindingMode,如果用java写,其实就是调用ActivityDataBindingBinding的setDataBindingMode方法,将数据modle传进去,里面会将用到的数据绑定到布局上,如果你想查看ActivityDataBindingBinding可以反编译你的apk,得到dex转jar查看。ActivityDataBindingBinding的实现类ActivityDataBindingBindingImpl也可以“build/source/kapt”目录下找到或者全局搜索,实现比较简单,自行查看。
更多用法
完成参考:data-binding
- 运算符和关键字的使用
下面是部分,更多参考官网android:maxEms="@{(5+1-2)/2*15%8*10}" android:text="@{dataBindingMode.name + TimeUtils.getAge(dataBindingMode.birth)}" // Logical && || android:includeFontPadding="@{(true || false) && includeFontPadding}" android:linksClickable="@{includeFont == 1}" android:focusable="@{includeFont > 1}" // Comparison == > < >= <= (Note that < needs to be escaped as <) android:enabled="@{includeFont < 1}" android:clickable="@{includeFont >= 2}" android:contextClickable="@{includeFont <= 2}" // Ternary operator ?: android:visibility="@{includeFont > 13 ? View.GONE : View.VISIBLE}" // Array access [] android:hint="@{list[index] + map[`firstName`]}" android:hint='@{list[index] + map["firstName"]}' // 字符串格式化,需要在xml定义nameFormat android:text='@{@string/nameFormat("pds", "ps")}'
- 绑定方法
<TextView ... android:onClick="@{handlers::onClickFriend}" app:isGone="@{true}" /> <Button ... android:onClick="@{(v) -> presenter.onCompletedChanged(dataBindingMode, false)}" />
class Presenter{ companion object{ private const val TAG = "Presenter" } fun onCompletedChanged(dataBindingMode: DataBindingMode, completed: Boolean){ Log.e(TAG,"onCompletedChanged") dataBindingMode.firstName.set("丘比特") dataBindingMode.birth = "1999-06-17" } }
- 数据观察
当'firstName'数据发生改变时,会自动更新到UI,同时可以添加firstName'改变监听data class DataBindingMode(val name: String){ var firstName = ObservableField<String>() }
上面时对字段使用,当然可以让数据类继承'BaseObservable'private fun initObserve() { dataBindingMode.firstName.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback(){ override fun onPropertyChanged(sender: Observable?, propertyId: Int) { Log.e(TAG,"onPropertyChanged:${propertyId}") } }) }
@get:Bindable用于在BR生成字段对应的id,在上面给字段添加数据改变监听的回调里面就会返回字段的id。class User : BaseObservable() { // @get:Bindable用于在BR生成字段 @get:Bindable var firstName: String = "" set(value) { field = value notifyPropertyChanged(BR.firstName) } @get:Bindable var lastName: String = "" set(value) { field = value notifyPropertyChanged(BR.lastName) } }
- 绑定适配器
- 定义适配器类
@BindingAdapter("imageFromUrl") fun bindImageFromUrl(view: ImageView, imageUrl: String?) { Log.e(TAG,"fun:bindImageFromUrl") if (!imageUrl.isNullOrEmpty()) { Glide.with(view.context) .load(imageUrl) .transition(DrawableTransitionOptions.withCrossFade()) .into(view) } } @BindingAdapter("isGone") fun bindIsGone(view: View, isGone: Boolean) { if (isGone){ view.visibility = View.VISIBLE }else{ view.visibility = View.GONE } }
- 绑定适配器
- 布局使用
isGone方法有个默认参数'view',如果适配器方法需要传递多个字段,那么改怎么写呢?<ImageView ... app:imageFromUrl="@{dataBindingMode.imageUrl}"/> <TextView ... app:isGone="@{true}"/>
@BindingAdapter("imageUrl", "error") fun loadImage(view: ImageView, url: String, error: Drawable) { Picasso.get().load(url).error(error).into(view) }
DataBinding提供的适配器,可以查看'databindng-adapter'适配器库<ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" />
- 补充
@BindingConversion将其它类型转换成另一种类型,使用方法请查看databinding中的Converters类。
@BindingMethods,@BindingMethod用于适配属性名和设置方法名不同属性方法。
理解原理
这部分可以自己去查看,使用DataBinding生成的对应实现类。