dataBinding总结

简介

dataBindingandroid支持的一种MVVM框架,使代码逻辑结构更为清晰。

使用

基本数据绑定

第一步 将layout变为dataBinding的结构。打开布局文件,选中根布局的 ViewGroup,按住 Alt + 回车键,点击 “Convert to data binding 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.leavesc.databinding_demo.model.User" />
        <import type="com.leavesc.databinding_demo.StringUtils" /> <!--引入工具类-->
        <variable
            name="userInfo"
            type="User" /><!--引入普通model-->
         <variable
            name="list"
            type="ObservableList&lt;String&gt;"/><!--引入list,当有尖括号时要转义-->
        <variable
            name="map"
            type="ObservableMap&lt;String,String&gt;"/><!--引入map,,当有尖括号时要转义-->
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="20dp"
        android:orientation="vertical"
        tools:context="com.leavesc.databinding_demo.Main2Activity">

        <TextView
            android:id="@+id/tv_userName"
            ···
            android:text="@{userInfo.name}" />

        <TextView
            ···
            android:text="@{userInfo.password}" />

    </LinearLayout>

</layout>

修改完成后,会多出data标签,data标签负责搭建了 View 和 Model 之间的通道
data需要引入变量和类型,如下所示

<data>
        <import type="com.leavesc.databinding_demo.model.User" />
        <import type="com.leavesc.databinding_demo.StringUtils" /> <!--引入工具类-->
        <variable
            name="userInfo"
            type="User" /><!--引入普通model-->
         <variable
            name="list"
            type="ObservableList&lt;String&gt;"/><!--引入list,当有尖括号时要转义-->
        <variable
            name="map"
            type="ObservableMap&lt;String,String&gt;"/><!--引入map,,当有尖括号时要转义-->
</data>

data的使用

android:text="@{userInfo.name,default=defaultValue}" <!--默认值只在预览时有效-->
android:text="@{String.valueOf(goods.price)}"<!--支持表达式-->
android:onClick="@{()->goodsHandler.changeGoodsName()}"<!--lambda表达式-->
android:text="@{StringUtils.toUpperCase(userInfo.name)}" <!--引用静态方法-->
android:visibility="@{user.male  ? View.VISIBLE : View.GONE}" <!--控制属性-->
android:afterTextChanged="@{userPresenter.afterTextChanged}" <!--要求方法的参数返回值与原函数保持一致-->
android:text="@{list.size() > 0 ? list[0].childrenNick : @string/login_new_child}"<!--list集合的使用-->

xml中通过@{userInfo.name}这种形式和数据类型的绑定。但具体要绑定哪一个变量,见下面。

第二步 此时,已经完成了数据绑定,但具体是哪个数据,需要显示指定,
在代码中,需要activity fragment要用ViewDataBinding来实现。

   private User user;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMain2Binding activityMain2Binding = DataBindingUtil.setContentView(this, R.layout.activity_main2); //ViewDataBinding子类,会自动生成
        user = new User("leavesC", "123456");
        activityMain2Binding.setUserInfo(user); //显示绑定具体的变量
    }

这种数据绑定,是一次性的,即当数据发生改变时,View并不会发生变化。如果需要View跟着数据变化,见下面。

单向数据绑定

有两个方式,

  • 方式一,继承BaseObservable,并添加相应注解,get/set方法,其中set方法要调用通知方法noifyXXX。
  • 方式二,使用ObservableField,这种方式直接定义相应变量即可。

方式一:继承BaseObservable,需要在相应的变量(public)或get方法加上@Bindable注解。set方法,要调用notifyChange()(会刷新所有的值域) 或 notifyPropertyChanged(BR.name) 只更新对应 BRflag.

方式二:ObservableField 可以理解为官方对 BaseObservable 中字段的注解和刷新等操作的封装,官方原生提供了对基本数据类型的封装,例如 ObservableBooleanObservableByteObservableCharObservableShortObservableIntObservableLongObservableFloatObservableDouble 以及 ObservableParcelable,也可通过 ObservableField 泛型来申明其他类型。
ObservableCollection dataBinding 也提供了包装类用于替代原生的 ListMap,分别是 ObservableListObservableMap,当其包含的数据发生变化时,绑定的视图也会随之进行刷新

这时,已经实现了当data发生改变时,view也会相应的更改,但是如果view的内容发生改变(如果EditText等),怎样映射到data呢?见下面双向绑定。

监听ObservableField

Observable变化时,view内容会发生改变。
有时,我们会灵活监听Observable的变化,比如,自己创建出来的view,让他跟Observable绑定,可以使用

observable.addOnPropertyChangedCallback(callback)

双向绑定

双向绑定只是xml中写法不同,如下,在@后加一个=

android:text="@={goods.name}"

dataBinding XML一些语法

android:text="@{user.name ?? user.password}" <!--会取第一个不为null的值,等价于-->
android:text="@{user.name != null ? user.name : user.password}"<!--功能同上-->

dataBinding会避免空指针异常

viewStubinclude中的使用

viewStubinclude一样支持dataBinding
viewStubincludebinding data通过父布局导入

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:bind="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <import type="com.leavesc.databinding_demo.model.User" />
        <variable
            name="userInfo"
            type="User" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".Main6Activity">
        
        <include
            layout="@layout/view_include"
            bind:userInfo="@{userInfo}" /><!--注意这里,将父布局的data传给子布局-->
    </LinearLayout>
</layout>

view_include.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <import type="com.leavesc.databinding_demo.model.User" />
        <variable
            name="userInfo"
            type="User" />
    </data>

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#acc">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:padding="20dp"
            android:text="@{userInfo.name}" />

    </android.support.constraint.ConstraintLayout>
</layout>

对于viewStub也可以在加载时,将数据binding data传入

activityMain6Binding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
            @Override
            public void onInflate(ViewStub stub, View inflated) {
                //如果在 xml 中没有使用 bind:userInfo="@{userInf}" 对 viewStub 进行数据绑定
                //那么可以在此处进行手动绑定
                ViewStubBinding viewStubBinding = DataBindingUtil.bind(inflated);
                viewStubBinding.setUserInfo(user);
                Log.e(TAG, "onInflate");
            }
        });

bindingAdapter

BindingAdapter 是一个注解用于支持自定义属性,或者扩展已有的属性。

  • 注解名为xml属性值。
  • 方法名,可以任意,参数,第一个为View,第二个为属性值。
    @BindingAdapter({"url"})
    public static void loadImage(ImageView view, String url) {
        Log.e(TAG, "loadImage url : " + url);
    }

然后,在xml中就可以这样来使用。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:bind="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <import type="com.leavesc.databinding_demo.model.Image" />
        <variable
            name="image"
            type="Image" />
    </data>

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".Main8Activity">

        <ImageView
            android:id="@+id/image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_launcher_background"
            bind:url="@{image.url}" /><!--xml中对bindingAdapter的使用-->
        
    </android.support.constraint.ConstraintLayout>
</layout>

BindingConversion

一种注解,用于类型转化,例如,通过对属性值转换为所需要的类型。

    @BindingConversion
    public static String conversionString(String text) {
        return text + "-conversionString";
    }

在xml中的使用

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text='@{"xxx"}'
            android:textAllCaps="false"/>
            <!--注意text即为bindingConversion在xml中的使用-->

引用资源文件

    <data>
        <variable
            name="flag"
            type="boolean" />
    </data>       
	<Button
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:paddingLeft="@{flag ? @dimen/paddingBig:@dimen/paddingSmall}"
         android:text='@{@string/format("leavesC", "Ye")}'
         android:textAllCaps="false" />

参考资料

dataBinding从入门到进阶

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值