Android DataBinding from getting started to advanced

DataBinding is a framework officially released by Google. As its name suggests, it is data binding. It is an implementation of MVVM mode on Android. It is used to reduce the coupling between layout and logic and make the code logic clearer. Compared with MVP, MVVM actually replaces the Presenter layer with the ViewModel layer. DataBinding can omit the findViewById() step we have been doing all along and greatly reduce the code in the Activity. The data can be bound to the layout file one way or two ways, which helps to prevent memory leakage. In addition, it can automatically perform null detection to avoid null pointer exceptions

The method to enable DataBinding is in the build.xml of the corresponding Model Add the following code to the gradle file to introduce support for DataBinding after synchronization

android {
    dataBinding {
        enabled = true
    }
}

1, Basic introduction

After enabling DataBinding, let's take a look at how to bind the specified variables in the layout file

Open the layout file, select the ViewGroup of the root layout, press Alt + enter, and click "Convert to data binding layout" to generate the layout rules required for DataBinding

<?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>

    </data>

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    </android.support.constraint.ConstraintLayout>
</layout>

The difference from the original layout is that there is an additional layout tag to wrap the original layout. The data tag is used to declare the variables and variable types to be used. To implement the MVVM ViewModel, you need to bind the data (Model) to the UI (View). The data tag acts like a bridge to build a channel between the View and the Model

Let's declare a mode first

package com.leavesc.databinding_demo.model;

/**
 * Author: ye should be ye
 * Time: 20:20, May 16, 2018
 * Description: https://github.com/leavesC
 */
public class User {

    private String name;

    private String password;
    
    ···
}

Declare the variable name and the full path of the class to be used in the data tag

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

If the User type needs to be used in many places, you can also import it directly, so that you don't have to specify the whole package name path every time The classes in lang. * package will be imported automatically, so they can be used directly

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

If the class name of import is the same, alias can be used to specify the alias

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

Here, a User type variable userInfo is declared. What we need to do is to hook this variable with two TextView controls. By setting the variable value of userInfo, we can make TextView display the corresponding text. The complete layout code is as follows

<?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" />
        <variable
            name="userInfo"
            type="User" />
    </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>

By @ {userInfo.name} making TextView reference to relevant variables, DataBinding will map it to the corresponding getter method. After that, you can set the layout file through DataBindingUtil in the Activity, omit the setContentView() method of the original Activity, and assign a value to the variable userInfo

    private User user;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMain2Binding activityMain2Binding = DataBindingUtil.setContentView(this, R.layout.activity_main2);
        user = new User("leavesC", "123456");
        activityMain2Binding.setUserInfo(user);
    }

Because @ {userInfo.name} does not have a clear value in the layout file, nothing will be displayed in the preview view, making it difficult to observe attributes such as text size and font color. At this time, you can set a default value for it (attributes such as text content or font size are applicable). The default value will only be displayed in the preview view, and the default value cannot contain quotation marks

    android:text="@{userInfo.name,default=defaultValue}"

In addition, you can also directly obtain the control with the specified ID through ActivityMain2Binding

    activityMain2Binding.tvUserName.setText("leavesC");

Each data binding layout file will generate a binding class. The instance name of ViewDataBinding is generated according to the layout file name. Change it to the hump naming method with initial capital letters, and omit the underline contained in the layout file name. Control is obtained in a similar way, but with a lowercase initial

You can also customize the instance name of ViewDataBinding in the following ways

    <data class="CustomBinding">

    </data>

In addition, a special variable named context will be generated as needed in the binding expression. The value of context is the context object returned by the getContext() method of the root View, and the context variable will be overwritten by the explicit variable declaration with this name

Data binding is also supported in Fragment and RecyclerView. For example, you can see the use of data binding in Fragment

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        FragmentBlankBinding fragmentBlankBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_blank, container, false);
        fragmentBlankBinding.setHint("Hello");
        return fragmentBlankBinding.getRoot();
    }

**In the above implementation of data binding, whenever the bound variable changes, you need to re pass the new variable value to ViewDataBinding to refresh the UI. Next, let's look at how to automatically refresh the UI**

2, One way data binding

There are three ways to automatically drive UI refresh by data change: BaseObservable, ObservableField and ObservableCollection

BaseObservable

After a pure ViewModel class is updated, the UI will not be updated automatically. After data binding, we naturally hope that the UI will refresh immediately after data changes. Observable is the concept born for this

BaseObservable provides notifyChange() and notifyPropertyChanged(). The former will refresh all value fields, while the latter will only update the flag of the corresponding br. The BR is generated through the annotation @ Bindable, and the view associated with a specific attribute can be generated through BR notify

/**
 * Author: ye should be ye
 * Time: 20:54, May 16, 2018
 * Description:
 */
public class Goods extends BaseObservable {

    //If it is a public modifier, you can add @ Bindable annotation directly above the member variable
    @Bindable
    public String name;

    //If it is a private modifier, add the @ Bindable annotation on the get method of the member variable
    private String details;

    private float price;

    public Goods(String name, String details, float price) {
        this.name = name;
        this.details = details;
        this.price = price;
    }

    public void setName(String name) {
        this.name = name;
        //Update this field only
        notifyPropertyChanged(com.leavesc.databinding_demo.BR.name);
    }

    @Bindable
    public String getDetails() {
        return details;
    }

    public void setDetails(String details) {
        this.details = details;
        //Update all fields
        notifyChange();
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

}

Only this field is updated in the setName() method, while all fields are updated in the setDetails() method

Add two buttons to change the three attribute values of the goods variable, so you can see the difference between the two notify methods. The button click event binding involved will also be discussed below

<?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.Goods" />
        <import type="com.leavesc.databinding_demo.Main3Activity.GoodsHandler" />
        <variable
            name="goods"
            type="Goods" />
        <variable
            name="goodsHandler"
            type="GoodsHandler" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="20dp"
        tools:context=".Main3Activity">

        <TextView
            ···
            android:text="@{goods.name}" />

        <TextView
            ···
            android:text="@{goods.details}" />

        <TextView
            ···
            android:text="@{String.valueOf(goods.price)}" />

        <Button
            ···
            android:onClick="@{()->goodsHandler.changeGoodsName()}"
            android:text="change attributes name and price"
            android:textAllCaps="false" />

        <Button
            ···
            android:onClick="@{()->goodsHandler.changeGoodsDetails()}"
            android:text="change attributes details and price"
            android:textAllCaps="false" />

    </LinearLayout>
</layout>
/**
 * Author: ye should be ye
 * Time: 21:07, May 16, 2018
 * Description:
 */
public class Main3Activity extends AppCompatActivity {

    private Goods goods;

    private ActivityMain3Binding activityMain3Binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);
        activityMain3Binding = DataBindingUtil.setContentView(this, R.layout.activity_main3);
        goods = new Goods("code", "hi", 24);
        activityMain3Binding.setGoods(goods);
        activityMain3Binding.setGoodsHandler(new GoodsHandler());
    }

    public class GoodsHandler {

        public void changeGoodsName() {
            goods.setName("code" + new Random().nextInt(100));
            goods.setPrice(new Random().nextInt(100));
        }

        public void changeGoodsDetails() {
            goods.setDetails("hi" + new Random().nextInt(100));
            goods.setPrice(new Random().nextInt(100));
        }

    }

}

You can see that the refresh of the name view does not refresh the price view at the same time, but the refresh of the details view also refreshes the price view

Classes that implement the Observable interface allow a listener to be registered. When the properties of Observable objects change, the listener will be notified. In this case, OnPropertyChangedCallback is required

Among them, propertyId is used to identify specific fields

        goods.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
            @Override
            public void onPropertyChanged(Observable sender, int propertyId) {
                if (propertyId == com.leavesc.databinding_demo.BR.name) {
                    Log.e(TAG, "BR.name");
                } else if (propertyId == com.leavesc.databinding_demo.BR.details) {
                    Log.e(TAG, "BR.details");
                } else if (propertyId == com.leavesc.databinding_demo.BR._all) {
                    Log.e(TAG, "BR._all");
                } else {
                    Log.e(TAG, "unknown");
                }
            }
        });

ObservableField

Inheriting from the Observable class is relatively restrictive, and the notify operation is also required. Therefore, you can choose to use ObservableField for simplicity. ObservableField can be understood as the official encapsulation of operations such as annotation and refresh of fields in BaseObservable. The official native provides encapsulation of basic data types, such as ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble and ObservableParcelable, Other types can also be declared through the ObservableField generic

/**
 * Author: ye should be ye
 * Time: 21:33, May 13, 2018
 * Description:
 */
public class ObservableGoods {

    private ObservableField<String> name;

    private ObservableFloat price;

    private ObservableField<String> details;

    public ObservableGoods(String name, float price, String details) {
        this.name = new ObservableField<>(name);
        this.price = new ObservableFloat(price);
        this.details = new ObservableField<>(details);
    }

}

yes ObservableGoods Changes in attribute values are triggered immediately UI Refresh, conceptually and Observable The difference is not big. See the source code provided below for the specific effect, which will not be repeated here

ObservableCollection
--------------------

dataBinding Wrapper classes are also provided to replace native `List` and `Map`,namely `ObservableList` and `ObservableMap`,When the data it contains changes, the bound view will also be refreshed

<?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="android.databinding.ObservableList"/>
    <import type="android.databinding.ObservableMap"/>
    <variable
        name="list"
        type="ObservableList&lt;String&gt;"/>
    <variable
        name="map"
        type="ObservableMap&lt;String,String&gt;"/>
    <variable
        name="index"
        type="int"/>
    <variable
        name="key"
        type="String"/>
</data>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.leavesc.databinding_demo.Main12Activity">

    <TextView
        ···
        android:padding="20dp"
        android:text="@{list[index],default=xx}"/>

    <TextView
        ···
        android:layout_marginTop="20dp"
        android:padding="20dp"
        android:text="@{map[key],default=yy}"/>

    <Button
        ···
        android:onClick="onClick"
        android:text="Change data"/>

</LinearLayout>

</layout>

private ObservableMap<String, String> map;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityMain12Binding activityMain12Binding = DataBindingUtil.setContentView(this, R.layout.activity_main12);
    map = new ObservableArrayMap<>();
    map.put("name", "leavesC");
    map.put("age", "24");
    activityMain12Binding.setMap(map);
    ObservableList<String> list = new ObservableArrayList<>();
    list.add("Ye");
    list.add("leavesC");
    activityMain12Binding.setList(list);
    activityMain12Binding.setIndex(0);
    activityMain12Binding.setKey("name");
}

public void onClick(View view) {
    map.put("name", "leavesC,hi" + new Random().nextInt(100));
}
![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/82ad16b2c9ac47d7a601832da96f0b2e~tplv-k3u1fbpfcp-watermark.image)

3, Bidirectional data binding
========

Two way binding means that when the data changes, the view is refreshed at the same time, and when the view changes, the data can also be changed at the same time

Look at the following example when EditText When the input of changes, it will be synchronized to the variable at the same time `goods`,The method of binding variables has an equal sign more than one-way binding: `android:text="@={goods.name}"`

<?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.ObservableGoods"/>
    <variable
        name="goods"
        type="ObservableGoods" />
</data>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".Main10Activity">

    <TextView
        ···
        android:text="@{goods.name}" />

    <EditText
        ···
        android:text="@={goods.name}" />

</LinearLayout>

</layout>

public class Main10Activity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityMain10Binding activityMain10Binding = DataBindingUtil.setContentView(this, R.layout.activity_main10);
    ObservableGoods goods = new ObservableGoods("code", "hi", 23);
    activityMain10Binding.setGoods(goods);
}

}

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e3b139c6a9b744058ee56e249fafaca2~tplv-k3u1fbpfcp-watermark.image)

4, Event binding
======

Strictly speaking, event binding is also a kind of variable binding, except that the set variable is the callback interface. Event binding can be used for the following callback events

*   android:onClick
*   android:onLongClick
*   android:afterTextChanged
*   android:onTextChanged
*   ...

stay Activity Create a new one inside **UserPresenter** Class to declare **onClick()** and **afterTextChanged()** Event corresponding callback method

public class UserPresenter {

    public void onUserNameClick(User user) {
        Toast.makeText(Main5Activity.this, "user name:" + user.getName(), Toast.LENGTH_SHORT).show();
    }

    public void afterTextChanged(Editable s) {
        user.setName(s.toString());
        activityMain5Binding.setUserInfo(user);
    }

    public void afterUserPasswordChanged(Editable s) {
        user.setPassword(s.toString());
        activityMain5Binding.setUserInfo(user);
    }

}

<?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.MainActivity.UserPresenter" />
    <variable
        name="userInfo"
        type="User" />
    <variable
        name="userPresenter"
        type="UserPresenter" />
</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.MainActivity">

    <TextView
        ···
        android:onClick="@{()->userPresenter.onUserNameClick(userInfo)}"
        android:text="@{userInfo.name}" />

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

    <EditText
        ···
        android:afterTextChanged="@{userPresenter.afterTextChanged}"
        android:hint="user name" />

    <EditText
        ···
        android:afterTextChanged="@{userPresenter.afterUserPasswordChanged}"
        android:hint="password" />

</LinearLayout>

</layout>

The method reference method is similar to the method of calling a function. You can choose to keep the signature of the event callback method consistent:**@{userPresenter.afterTextChanged}**,At this time, the method name can be different, but the method parameters and return values must be consistent with the original callback function. You can also refer to functions that do not follow the default signature:**@{()->userPresenter.onUserNameClick(userInfo)}**,It's used here Lambda Expression, so that you can not follow the default method signature`userInfo`Object is returned directly to the click method. You can also use method references **::** Event binding in the form of ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/18d28b35a91747a0b8ea1aa8e42483c6~tplv-k3u1fbpfcp-watermark.image)

5, Using class methods
=======

First, define a static method

public class StringUtils {

public static String toUpperCase(String str) {
    return str.toUpperCase();
}

}

stay data Import the tool class from the tag

<import type="com.leavesc.databinding_demo.StringUtils" />

Then you can call it like a normal function

<TextView

 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:onClick="@{()->userPresenter.onUserNameClick(userInfo)}"
 android:text="@{StringUtils.toUpperCase(userInfo.name)}" />
6, Operator
=====

Base operator
-----

DataBinding The following operators, expressions, and keywords are supported in layout files

*   arithmetic + - / \* %
*   String merge +
*   logic && ||
*   binary & | ^
*   one yuan + - ! ~
*   displacement >> >>> <<
*   compare == > < >= <=
*   Instanceof
*   Grouping ()
*   character, String, numeric, null
*   Cast
*   Method call
*   Field visit
*   Array visit \[\]
*   three yuan ?:

The following operations are not currently supported

*   this
*   super
*   new
*   Show generic calls

In addition, DataBinding The following forms of calls are also supported

Null Coalescing
---------------

null coalescing operator  **??** Will take the first not as null As the return value

<TextView

 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="@{user.name ?? user.password}" />
Equivalent to
android:text="@{user.name != null ? user.name : user.password}"
Attribute control
----

Can be controlled by variable values View Properties of

<TextView

 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="Visibility change"
 android:visibility="@{user.male  ? View.VISIBLE : View.GONE}" />
Avoid null pointer exceptions
-------

DataBinding It will also automatically help us avoid null pointer exceptions, for example, if **"@{userInfo.password}"** in **userInfo** by **null** If so,**userInfo.password** Will be assigned the default value **null**,No null pointer exception will be thrown

VII include and viewStub
====================

include
-------

about include The layout file is also supported through dataBinding For data binding, you also need to wait for include Is still used in the layout layout Tag to declare the variables to be used

`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>

In the main layout file, the corresponding variables are passed to include Layout so that the same variable is shared between two layout files

<?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}" />
    
</LinearLayout>

</layout>

viewStub
--------

dataBinding Same support ViewStub layout

Reference in layout file viewStub layout

<ViewStub

    android:id="@+id/view_stub"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout="@layout/view_stub"/>
Get ViewStub Object, which can be controlled ViewStub Visibility of
ActivityMain6Binding activityMain6Binding = DataBindingUtil.setContentView(this, R.layout.activity_main6);
View view = activityMain6Binding.viewStub.getViewStub().inflate();
If necessary ViewStub Bind variable values, then ViewStub Use the same file layout Label for layout, and the main layout file uses custom bind Namespace passes variables to ViewStub
<ViewStub
    android:id="@+id/view_stub"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout="@layout/view_stub"
    bind:userInfo="@{userInfo}" />
If in xml Not used in `bind:userInfo="@{userInf}"` yes ViewStub For data binding, you can wait until when ViewStub **Inflate** Bind the variable when. In this case, it needs to be ViewStub set up `setOnInflateListener`Callback function, data binding in callback function
    activityMain6Binding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
        @Override
        public void onInflate(ViewStub stub, View inflated) {
            //If you do not use bind:userInfo="@{userInf}" to bind viewStub in xml
            //Then you can bind manually here
            ViewStubBinding viewStubBinding = DataBindingUtil.bind(inflated);
            viewStubBinding.setUserInfo(user);
            Log.e(TAG, "onInflate");
        }
    });
VIII BindingAdapter
================

dataBinding Provided **BindingAdapter** This annotation is used to support custom attributes or modify existing attributes. Annotation values can be existing xml Properties, such as `android:src`,`android:text`And so on, you can also customize the properties, and then xml Used in

For example, for a ImageView ,We hope that when the value of a variable changes, we can dynamically change the displayed picture. At this time, we can BindingAdapter To achieve

You need to define a static method and add BindingAdapter Annotation, the annotation value is ImageView Control, and the two parameters of the static method can be understood as follows: when ImageView Control url When the attribute value changes, dataBinding Will ImageView Examples and new url Value passed to loadImage() Method so that it can be changed dynamically here ImageView Related properties of
@BindingAdapter({"url"})
public static void loadImage(ImageView view, String url) {
    Log.e(TAG, "loadImage url : " + url);
}
stay xml The associated variable value in the file, bind This name can be customized

<?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}" />
    
</android.support.constraint.ConstraintLayout>

</layout>

BindingAdapter A more powerful point is that it can be covered Android The original control properties. For example, you can set each Button All text should be suffixed:“-Button"
@BindingAdapter("android:text")
public static void setText(Button view, String text) {
    view.setText(text + "-Button");
}
<Button
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:onClick="@{()->handler.onClick(image)}"
   android:text='@{"Change picture Url"}'/>
In this way, it is used in the whole project **"android:text"** The text displayed by the control with this property will have an additional suffix

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ab15c8b93c8d4bfca4976b6b271b3247~tplv-k3u1fbpfcp-watermark.image)

IX BindingConversion
===================

dataBinding It also supports data conversion or type conversion

And BindingAdapter Similarly, the following method will convert all in the layout file to`@{String}`Referenced by`String`Type variable with suffix`-conversionString`
@BindingConversion
public static String conversionString(String text) {
    return text + "-conversionString";
}
xml file
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text='@{"xxx"}'
        android:textAllCaps="false"/>
![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/129da4953fd848e3a25906df52077ac1~tplv-k3u1fbpfcp-watermark.image)

As you can see, for Button For example, BindingAdapter and BindingConversion At the same time, and BindingConversion Your priority is higher

In addition, BindingConversion It can also be used to convert the type of attribute value

Look at the following layout, here `background` and `textColor` When two attributes are assigned, the string is directly used. Normally, this will naturally report an error, but with BindingConversion After, you can automatically convert the value of string type to the required value `Drawable` and `Color` Yes
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background='@{"gules"}'
        android:padding="20dp"
        android:text="Blue characters on red background"
        android:textColor='@{"blue"}'/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:background='@{"blue"}'
        android:padding="20dp"
        android:text="Red characters on a blue background"
        android:textColor='@{"gules"}'/>
@BindingConversion
public static Drawable convertStringToDrawable(String str) {
    if (str.equals("gules")) {
        return new ColorDrawable(Color.parseColor("#FF4081"));
    }
    if (str.equals("blue")) {
        return new ColorDrawable(Color.parseColor("#3F51B5"));
    }
    return new ColorDrawable(Color.parseColor("#344567"));
}

@BindingConversion
public static int convertStringToColor(String str) {
    if (str.equals("gules")) {
        return Color.parseColor("#FF4081");
    }
    if (str.equals("blue")) {
        return Color.parseColor("#3F51B5");
    }
    return Color.parseColor("#344567");
}
![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4f3612b6494e40ea9e4d7477aea14f5b~tplv-k3u1fbpfcp-watermark.image)

X Array,List,Set,Map ...
========================

dataBinding It is also supported in layout files **Array Lsit,Set and Map**,And it can be used in the layout file `list[index]` To get the element

And for and **variable** Labels are separated by angle brackets in the declaration **Lsit< String >** The escape character of angle brackets is required when using data types such as

<?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="java.util.List" />
    <import type="java.util.Map" />
    <import type="java.util.Set" />
    <import type="android.util.SparseArray" />
    <variable
        name="array"
        type="String[]" />
    <variable
        name="list"
        type="List&lt;String&gt;" />
    <variable
        name="map"
        type="Map&lt;String, String&gt;" />
    <variable
        name="set"
        type="Set&lt;String&gt;" />
    <variable
        name="sparse"
        type="SparseArray&lt;String&gt;" />
    <variable
        name="index"
        type="int" />
    <variable
        name="key"
        type="String" />
</data>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".Main7Activity">

    <TextView
        ···
        android:text="@{array[1]}" />
    <TextView
        ···
        android:text="@{sparse[index]}" />
    <TextView
        ···
        android:text="@{list[index]}" />
    <TextView
        ···
        android:text="@{map[key]}" />
    <TextView
        ···
        android:text='@{map["leavesC"]}' />
    <TextView
        ···
        android:text='@{set.contains("xxx")?"xxx":key}' />
</LinearLayout>

</layout>

11, Resource reference
=======

dataBinding Supports access to resources such as sizes and strings

`dimens.xml`
<dimen name="paddingBig">190dp</dimen>
<dimen name="paddingSmall">150dp</dimen>
`strings.xml`
<string name="format">%s is %s</string>
<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" />
yes DataBinding This is the end of the introduction. Of course, there must be some missing knowledge points, but in general, I think I have made it very clear, and the rest will be added in the future

Here is a download of the above sample code, or you can GitHub Give me a Star?

Project Home  -> [DataBinding\_Demo](https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2FleavesC%2FDataBinding_Demo "https://github.com/leavesC/DataBinding_Demo")

 #### Relevant video recommendations:

[[2021 Latest edition] Android studio Installation tutorial+Android(Android zero foundation tutorial video (suitable for Android 0 Basics, Android Beginner (including audio and video)_Bilibili_bilibili](https://www.bilibili.com/video/BV1Jb4y187C4?spm_id_from=333.999.0.0)

[Golden three silver four interview peak must ask MVVM Of Technology databinding_Bilibili_bilibili](https://www.bilibili.com/video/BV19b4y1t71c?spm_id_from=333.999.0.0)

[[ Android Advanced tutorial]—— Jetpack DataBinding Application and principle_Bilibili_bilibili](https://www.bilibili.com/video/BV11M4y1w7CU?spm_id_from=333.999.0.0)

Keywords: Android Programmer DataBinding

Added by stormx on Wed, 12 Jan 2022 21:46:41 +0200