Android Jetpack之DataBinding
目录
简单介绍
DataBinding是Google在2015年的I/O大会上提出的,DataBinding可以帮助Android更好的实现MVVM架构,而且还可以省略像findViewById这样的代码,进一步降低了页面与布局文件直接的耦合度。
使用方法
1.开启DataBinding
在app的build.gradle文件中增加如下代码
android {
......
dataBinding{
enabled = true
}
}
2.简单的数据绑定
在开启了DataBinding之后我们可以在需要用到DataBinding的布局文件中,将鼠标移动到根标签上,就会自动提示让你点击变成DataBinding需要的格式
这时候我们把需要绑定的数据在data标签中进行声明,而自定义的数据类型需要写全类名,数据的使用需要用@{},如下所示
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<!-- 基本数据类型 -->
<variable
name="price"
type="int" />
<!-- 自定义数据类型 -->
<variable
name="book"
type="com.example.databindingdemo.bean.Book" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:textSize="20sp"
android:text="@{book.name}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:textSize="20sp"
android:text="@{`价格¥:` + price}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</layout>
其中Book类如下
public class Book {
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在Activity中绑定数据需要使用DataBindingUtil的setContentView方法,它会返回一个ViewDataBinding的对象,这里我们用的是系统自动生成的实现类,它生成的规则其实就是根据布局文件的名称来生成的,如下所示
public class SimpleDataBindingActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivitySimpledatabindingBinding activitySimpledatabindingBinding = DataBindingUtil.setContentView(this,R.layout.activity_simpledatabinding);
activitySimpledatabindingBinding.setBook(new Book("《斗罗大陆》"));
activitySimpledatabindingBinding.setPrice(12);
}
}
运行后的结果如下
3.引入静态类
在绑定数据的过程中我们可能需要对数据进行转化,因此我们可以通过引入静态类来实现,这里我们用的是import标签,如下所示
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<!-- 引入静态类 -->
<import type="com.example.databindingdemo.util.DateUtil"/>
<!-- 基本数据类型 -->
<variable
name="week"
type="int" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:textSize="20sp"
android:text="@{DateUtil.getWeek(week)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</layout>
其中DateUtil类如下
public class DateUtil {
/**
* 获取星期
* @return
*/
public static String getWeek(int num){
switch (num){
case 1:
return "星期一";
case 2:
return "星期二";
case 3:
return "星期三";
case 4:
return "星期四";
case 5:
return "星期五";
case 6:
return "星期六";
default:
return "星期天";
}
}
}
Activity中的使用如下:
public class ImportDataBindingActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityImportdatabindingBinding activityImportdatabindingBinding = DataBindingUtil.setContentView(this,R.layout.activity_importdatabinding);
activityImportdatabindingBinding.setWeek(1);
}
}
执行结果如下
4.绑定点击事件
这里绑定的是一个包含了点击事件的Model类,如下所示
public class MainClickModel {
private Context mContext;
public MainClickModel(Context mContext) {
this.mContext = mContext;
}
/**
* 跳转简单绑定数据页面
* @param view
*/
public void onClickSimpleDataBinding(View view){
mContext.startActivity(new Intent(mContext, SimpleDataBindingActivity.class));
}
}
我们在布局文件中需要在onClick属性中增加绑定
<?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"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="mainClickModel"
type="com.example.databindingdemo.model.MainClickModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:text="简单数据绑定"
android:onClick="@{mainClickModel.onClickSimpleDataBinding}"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</layout>
点击按钮效果如下
5.自定义BindingAdapter
DataBinding内部的数据填充都是通过BindingAdapter实现的,这里我们也可以通过自定义BindingAdapter来实现自己想要的功能,比如我们可以自定义一个ImageBindingAdapter来给ImageView添加网络图片
public class ImageBindingAdapter {
@BindingAdapter("netImage")
public static void setNetImage(ImageView imageView,String imgUrl){
Glide.with(imageView).load(imgUrl).into(imageView);
}
}
布局文件如下,需要用app命名空间来使用自己自定义的BindingAdapter,其中名称要和自定义的BindingAdapter中@BindingAdapter注解中的名称一样
<?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="netImageUrl"
type="String" />
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
app:netImage="@{netImageUrl}"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</layout>
Activity中的代码如下
public class BindingAdapterActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityBindingadapterBinding activityBindingadapterBinding = DataBindingUtil.setContentView(this,R.layout.activity_bindingadapter);
activityBindingadapterBinding.setNetImageUrl("https://pic.netbian.com/uploads/allimg/180826/113958-1535254798fc1c.jpg");
}
}
运行效果如下
6.双向绑定
目前以上所实现的只是用于展示的单向绑定,如果我们使用的是EditText这样需要输入数据的控件,就需要使用双向绑定了,这里我们使用来包装数据,如下所示我们定义一个Model然后把要绑定的数据使用ObservableField包装起来,然后添加set和get方法通过ObservableField返回
public class ObservableFieldModel {
private String userName = "唐三";
private ObservableField<String> observableField;
public ObservableFieldModel() {
observableField = new ObservableField<>();
observableField.set(userName);
}
public String getUserName() {
return observableField.get();
}
public void setUserName(String userName) {
observableField.set(userName);
}
}
布局文件如下,这里不同的是双向绑定我们使用的是@={}
<?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="observableFieldModel"
type="com.example.databindingdemo.model.ObservableFieldModel" />
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/et"
android:textSize="20sp"
android:text="@={observableFieldModel.userName}"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</layout>
Activity中的的逻辑如下,给EditText增加了一个文字改变时的监听,当文字改变后打印出当前变量的值
public class ObservableFieldActivity extends AppCompatActivity {
private ObservableFieldModel observableFieldModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityObservablefieldBinding activityObservablefieldBinding = DataBindingUtil.setContentView(this,R.layout.activity_observablefield);
observableFieldModel = new ObservableFieldModel();
activityObservablefieldBinding.setObservableFieldModel(observableFieldModel);
((EditText)findViewById(R.id.et)).addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
Log.e("双向绑定",observableFieldModel.getUserName());
}
});
}
}
效果如下
补充
●字符串拼接
在布局文件中使用字符串拼接有如下几种方式
1.string format
其中name是布局文件中声明的变量
<!--一个字符串-->
<string name="Data_Text">Name is %s</string>
android:text= "@{@string/Data_Text(name)}"
<!--一个字符串-->
<string name="Data_names">Name1: %1$s,Name2:%2$s</string>
android:text= "@{@string/Data_names(name1, name2)}"
2.加号方式(直接拼接)
注意这里使用的不是单引号而是TAB键上面的那个键
android:text="@{`字符串:` + str}"
3.加号方式(string资源)
android:text="@{@string/app_name+book.name}"