Android Jetpack之DataBinding

2021-09-30  本文已影响0人  itfitness

目录

简单介绍

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}"

案例源码

https://gitee.com/itfitness/data-binding-demo

上一篇下一篇

猜你喜欢

热点阅读