Android DataBinding解析

作者: 金馆长说 | 来源:发表于2018-07-31 18:35 被阅读12次

github simpledemo
1. DataBinding特点

  • 这个库是在在2015年7月发布的Android Studio v1.3.0 版本上引入,在2016年4月Android Studio v2.0.0 上正式支持。目前为止,Data Binding 已经支持双向绑定了。
  • Data Binding 是一个support库,最低支持到Android 2.1(API Level 7+)。*

  • 之前我们对布局的操作一般是通过如 findViewById()、setText(),setVisibility(),setEnabled() 或 setOnClickListener() 等,一系列的逻辑可能都会写入到activity中或者其他mode中,binding库改进了这个流程,可以在布局中写逻辑,数据的绑定操作我们都可以在xml中编写了,不需要我们对控件进行任何赋值操作,这样极大的优化了代码的耦合度和简洁程度。

2. 基本使用

  • model级别的gradle加入
android {
....
 dataBinding {
        enabled true
    }
}
  • 基本的数据绑定
    对需要绑定的xml顶级布局使用<layout>标签,一个xml钟只能包含一个<data>标签,我们可以在data标签中import我们的类,或者通过variable声明我们的变量。

TextView的text使用了@{String.valueOf(user.age),text接收的是一个string所以需要转换下,引用格式为@{}。通过
variable中的name,我们可以和在正常java文件中一样使用这些字段变量了,包括import进来的类也是一样的,我们可以导入任何你需要使用的类。

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <import type="com.liangfeizc.databinding.model.User" />
        <import type="com.liangfeizc.databinding.utils.MyStringUtils" alias="StringUtils" />
        <import type="android.view.View" />

        <variable name="user" type="User" />
    </data>


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{String.valueOf(user.age)}" />
</layout>

代码中调用
通过DataBindingUtil的setContentView方法返回了一个ActivityBasicBinding对象,ActivityBasicBinding是通过xml自动生成的,编译器如何解决要生成类是通过<layout>这个标签来决定的。binding.setUser(user),这句代码之后(setUser是是xml中定义的variable的name自动生成出来的),数据就会自动设置到我们的view中了,不需要写入其他的设置View的逻辑了。

public class BasicActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ActivityBasicBinding binding = DataBindingUtil.setContentView(
                this, R.layout.activity_basic);
        User user = new User("fei", "Liang", 27);
        binding.setUser(user);
    }
}

3.includes嵌套layout的绑定
有时候我们的xml中可能会存在一些includ标签,引用其他的layout,这个时候数据的绑定该如何操作。

这是layout_btn_ok的xml,定义了二个变量在Button中使用了。

<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
    <data>

        <variable
            name="okText"
            type="String"/>

        <variable
            name="listener"
            type="com.liangfeizc.databinding.listener.OkListener"/>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:onClick="@{listener.onClickOk}"
            tools:text="ok"
            android:text="@{okText}"/>
    </LinearLayout>

</layout>

activity_main的xml,这个xml我们需要引用layout_btn_ok的布局。 main布局中我们也定义了和 btn布局中一样的变量值,如果有被引用布局而且布局中有使用变量,我们就需要在,引用布局中也声明和这个xml一样的值,进行绑定。通过bind:okText="@{okText}" bind:listener="@{listener}"这个二个bind我们就把值给传递到了btn布局中,这个布局就可以正常的使用变量了。

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:bind="http://schemas.android.com/apk/res-auto">

    <data>

        <import type="com.liangfeizc.databinding.model.User" />
        <variable
            name="user"
            type="User" />
        <variable
            name="listener"
            type="com.liangfeizc.databinding.listener.OkListener" />
        <variable
            name="okText"
            type="String" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">


        <include
            layout="@layout/layout_btn_ok"
            bind:okText="@{okText}"
            bind:listener="@{listener}"/>
    </LinearLayout>
</layout>

代码中使用

 ActivityIncludeBinding  binding = DataBindingUtil.setContentView(
                this, R.layout.activity_include);

        binding.setListener(this);
        binding.setOkText("to toast");
        User user = new User("test", "Liang");
        binding.setUser(user);

4.集合的使用
databinding也支持在xml中使用集合。

这里省略了<layout>标签

 <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:text="list[index]:" />
        <TextView
            android:text="@{list[index]}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:text="sparse[index]:" />
        <TextView
            android:text="@{sparse[index]}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:text="map[key]:" />
        <TextView
            android:text="@{map[key]}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <View
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="@android:color/black" />

        <TextView
            android:text='map["firstName"]'
            android:textStyle="bold"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <TextView
            android:text='@{map["firstName"]}'
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:text="map[`firstName`]"
            android:textStyle="bold"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <TextView
            android:text="@{map[`firstName`]}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:text="map[&amp;quot;firstName&amp;quot;]"
            android:textStyle="bold"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <TextView
            android:text="@{map[&quot;firstName&quot;]}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

只要数据更新,xml中的操作集合的逻辑就会起到作用。

 CollectionsBinding binding = DataBindingUtil.setContentView(
                this, R.layout.activity_collection);

        String[] literals = new String[]{"liang", "fei"};

        List<String> list = new ArrayList<>();
        SparseArray<String> sparse = new SparseArray<>(2);

        String key = "firstName";
        int index = 0;

        for (int i = 0; i < literals.length; i++) {
            list.add(literals[i]);
            sparse.put(0, literals[i]);
        }

        Map<String, String> map = new HashMap<>();
        map.put(key, "liang");
        map.put("lastName", "fei");

        binding.setIndex(index);
        binding.setKey(key);
        binding.setList(list);
        binding.setSparse(sparse);
        binding.setMap(map);

5.使用资源
dataBinding中也能支持使用各种资源文件,通过@dimen/largePaddin我们使用了dimen中的一个dm属性。一些string color Image 等资源都可以通过这种方式使用。

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data class="ResourceBinding">
        <variable name="large" type="boolean" />
       
    </data>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:padding="@{large? (int)@dimen/largePadding : (int)@dimen/smallPadding}"
            android:background="@android:color/black"
            android:textColor="@android:color/white"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/hello_world" />

       
    </LinearLayout>
</layout>


6. BindingAdapter注解
这个注解可以动态接收到xml中使用的属性

<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <import type="com.liangfeizc.databinding.sample.attributesetter.AttributeSettersActivity"/>

        <variable
            name="activity"
            type="AttributeSettersActivity"/>

        <variable
            name="imageUrl"
            type="String"/>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.liangfeizc.databinding.view.NameCard
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:layout_marginEnd="@dimen/largePadding"
            android:layout_marginLeft="@dimen/largePadding"
            android:layout_marginRight="@dimen/largePadding"
            android:layout_marginStart="@dimen/largePadding"
            android:gravity="center"
            app:age="27"
            app:firstName="@{@string/firstName}"
            app:lastName="@{@string/lastName}"/>

        <com.liangfeizc.avatarview.AvatarView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:error="@{@drawable/error}"
            app:imageUrl="@{imageUrl}"
            app:onClickListener="@{activity.avatarClickListener}"/>

    </LinearLayout>
</layout>

@BindingAdapter({"imageUrl", "error"}) 中的属性就是我们需要接收的属性,必须在xml中存在而且是以app:命名空间。方法名字必须是 public staitc方式命名,方法名没要求,参数值需要和属性中使用的值对应。参数可以需要一样。

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_attribute_setters);
        mBinding.setActivity(this);
        mBinding.setImageUrl(Randoms.nextImgUrl());
    }

    @BindingAdapter({"imageUrl", "error"})
    public static void loadImaasdge(ImageView view, String url, Drawable error) {
        Log.d(App.TAG, "load image");
        Picasso.with(view.getContext()).load(url).error(error).into(view);
    }

相关文章

网友评论

    本文标题:Android DataBinding解析

    本文链接:https://www.haomeiwen.com/subject/gqnhvftx.html