1. gradle.build配置
数据绑定库与 Android Gradle 插件捆绑在一起。您无需声明对此库的依赖项,但必须启用它。如需启用数据绑定,请在模块的build.gradle 文件中将 dataBinding 构建选项设置为 true,如下所示:
android {
...
buildFeatures {
dataBinding true
}
}
2.xml和代码(java或者kotlin)中示例
- xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 数据变量定义或者代码引用 -->
<data>
<import type="java.util.List"/>
<variable name="user" type="com.example.User"/>
</data>
<!-- UI layout's root element -->
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"/>
</LinearLayout>
</layout>
- 代码
kotlin
//数据对象定义
data class User(val firstName: String, val lastName: String)
//数据绑定
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
/*------------*/
val binding: ActivityMainBinding = DataBindingUtil.setContentView(
this, R.layout.activity_main)
//或者
val binding: ActivityMainBinding = ActivityMainBinding.inflate(getLayoutInflater())
/*------------*/
binding.user = User("Test", "User")
}
java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*------------*/
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
//或者
ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
/*------------*/
User user = new User("Test", "User");
binding.setUser(user);
}
如果您要在 Fragment、ListView 或 RecyclerView 适配器中使用数据绑定项,您可能更愿意使用绑定类或 DataBindingUtil 类的 inflate() 方法,如以下代码示例所示
kotlin
val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false)
// or
val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)
java
ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
// or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);
从上面可以知道数据绑定简单的实现,可以将数据绑定到xml中。但是还做不到数据变化时UI随之变化;也做不到UI中输入新的数据,绑定对象的数据也随之变化(双向绑定)
LiveData使用
配置
打开项目的 build.gradle 文件(而不是应用或模块的该文件)并添加 google() 代码库,如下所示:
allprojects {
repositories {
google()//新增
jcenter()
}
}
打开应用或模块的 build.gradle 文件,然后添加所需的软件工件作为依赖项。
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
创建 LiveData 对象
LiveData 是一种可用于任何数据的封装容器,其中包括可实现 Collections 的对象,如 List。LiveData 对象通常存储在 ViewModel 对象中,并可通过 getter 方法进行访问,如以下示例中所示:
class NameViewModel : ViewModel() {
// Create a LiveData with a String
val currentName: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
// Rest of the ViewModel...
}
观察 LiveData 对象
class NameActivity : AppCompatActivity() {
// Use the 'by viewModels()' Kotlin property delegate
// from the activity-ktx artifact
private val model: NameViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Other code to setup the activity...
// Create the observer which updates the UI.
val nameObserver = Observer<String> { newName ->
// Update the UI, in this case, a TextView.
nameTextView.text = newName
}
// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
model.currentName.observe(this, nameObserver)
}
}
更新 LiveData 对象
button.setOnClickListener {
val anotherName = "John Doe"
model.currentName.setValue(anotherName)
}
与LiveData功能相同的对象:继承 BaseObservable 或者使用 ObservableField
双向绑定只需要在xml中使用@=
<EditText
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:text="@={person.name}"/>
3. xml中的数据区域引用和UI事件绑定
集合引用和使用
<data>
<import type="android.util.SparseArray"/>
<import type="java.util.Map"/>
<import type="java.util.List"/>
<variable name="list" type="List<String>"/>
<variable name="sparse" type="SparseArray<String>"/>
<variable name="map" type="Map<String, String>"/>
<variable name="index" type="int"/>
<variable name="key" type="String"/>
</data>
…
android:text="@{list[index]}"
…
android:text="@{sparse[index]}"
…
android:text="@{map[key]}"
资源使用
android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
android:text="@{@string/nameFormat(firstName, lastName)}"
android:text="@{@plurals/send_flower(sendFlowerCount)}"
<!--string定义-->
<resources>
<string name="nameFormat">Full Name: %1$s%2$s</string>
<plurals name="send_flower">
<item quantity="one">send %1$s flower</item>
<item quantity="other">send %1$s flowers</item>
</plurals>
</resources>
事件处理
android:onClick="@{(view) -> presenter.onSaveClick(task)}"
自定义BindingAdapter属性绑定
通过属性绑定某个方法
//这个注解放在任何类上,最好是放在一些定义了BindingAdapter的类上,这样方便查找
@BindingMethods({
@BindingMethod(type = "android.widget.ImageView",
attribute = "android:tint",
method = "setImageTintList"),
})
定义imageUrl
@BindingAdapter(value = ["imageUrl", "placeholder"], requireAll = false)
fun setImageUrl(imageView: ImageView, url: String?, placeHolder: Drawable?) {
if (url == null) {
imageView.setImageDrawable(placeholder);
} else {
MyImageLoader.loadInto(imageView, url, placeholder);
}
}
使用imageUrl
<ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" />
对象转换
自动转换对象
当绑定表达式返回 Object 时,库会选择用于设置属性值的方法。Object 会转换为所选方法的参数类型。对于使用 ObservableMap 类存储数据的应用,这种行为非常便捷,如以下示例所示:
note:原始类型要能支持转换
<TextView
android:text='@{userMap["lastName"]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
自定义转换
在某些情况下,需要在特定类型之间进行自定义转换。例如,视图的 android:background 特性需要 Drawable,但指定的 color 值是整数。以下示例展示了某个属性需要 Drawable,但结果提供了一个整数:
<View
android:background="@{isError ? @color/red : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
每当需要 Drawable 且返回整数时,int 都应转换为 ColorDrawable。您可以使用带有 BindingConversion 注释的静态方法完成这个转换,如下所示:
@BindingConversion
public static ColorDrawable convertColorToDrawable(int color) {
return new ColorDrawable(color);
}
但是,绑定表达式中提供的值类型必须保持一致。您不能在同一个表达式中使用不同的类型,如以下示例所示:
<View
android:background="@{isError ? @drawable/error : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>