DataBinding is an Android implementation of the MVVM pattern, designed to reduce the coupling between layout and logic and make code logic clearer. MVVM, in contrast to MVP, replaces the Presenter layer with the ViewModel layer. DataBinding eliminates the findViewById() step we’ve been using, significantly reduces the code inside the Activity, helps prevent memory leaks by binding data one-way or two-way to layout files, and automatically does null detection to avoid null pointer exceptions

To enable DataBinding, add the following code to the build.gradle file of the corresponding Model and synchronize it to introduce support for DataBinding

android {
    dataBinding {
        enabled = true}}Copy the code

First, basic introduction

Now that DataBinding is enabled, let’s first look at how do I bind the specified variable in the layout file

Open the layout file, select the ViewGroup for the root layout, hold Alt + Enter, and click “Convert to DataBinding Layout” to generate the layout rules for the DataBinding


      
<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>
Copy the code

The data tag is used to declare the variables to be used and the type of variables. To implement the ViewModel of MVVM, you need to bind the data (Model) to the UI (View). The data tag acts as a bridge between the View and the Model

Let’s declare a Modle first

package com.leavesc.databinding_demo.model;

Should be/author: * * * / * time: 2018/5/16 * shall lie description: https://github.com/leavesC * /
public class User {

    private String name;

    privateString password; ...}Copy the code

Declare the name of the variable 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>
Copy the code

If you want to use the User type more than once, you can import it directly, so you don’t have to specify the entire package name path each time. The classes in the java.lang.* package are automatically imported, so you can use them directly

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

If there are cases where the import class names are the same, you can specify the alias using 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>
Copy the code

We declare a variable named userInfo of type User. All we need to do is hook this variable to two TextView controls. By setting the value of the userInfo variable and making the TextView display the corresponding text, the complete layout code is shown below


      
<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>
Copy the code

Using @{userinfo.name} to reference the TextView to the relevant variable, DataBinding will map it to the corresponding getter method. After that, you can set the layout file in your Activity using DataBindingUtil. Omit the original Activity’s setContentView() method 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);
    }
Copy the code

Since @{userinfo.name} does not have an explicit value in the layout file, nothing will be displayed in the preview view. It is not easy to observe the text size and font color properties. In this case, you can set the default value (text content or font size, etc.) to be displayed in the preview view. The default value cannot contain quotation marks

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

Alternatively, you can get the control with the specified ID directly through the ActivityMain2Binding

	activityMain2Binding.tvUserName.setText("leavesC");
Copy the code

Each data binding layout file generates a binding class. The ViewDataBinding instance name is generated from the layout file name, using a hump naming method with uppercase capitalization, and omits any underscores contained in the layout file name. Control is obtained in a similar manner, but starts with a lowercase letter

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

    <data class="CustomBinding">

    </data>
Copy the code

In addition, a special variable named context is generated as needed in the binding expression. The value of context is the context object returned by the root View’s getContext() method. The context variable is overridden by an explicit variable declaration with that name

Databinding is also supported in fragments and RecyclerView. For example, look at the use of Databinding in fragments

    @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();
    }
Copy the code

** In the above method of data binding, each time the bound variable changes, you need to pass the new variable value to the ViewDataBinding again to refresh the UI. Now, how do I automatically refresh the UI

Unidirectional data binding

There are three ways to implement automatic UI refresh driven by data changes: BaseObservable, ObservableField, and ObservableCollection

BaseObservable

When a pure ViewModel class is updated, it does not automatically update the UI. With data binding, we naturally expect the UI to refresh as soon as the data changes. Observable is the concept for this

BaseObservable provides notifyChange() and notifyPropertyChanged() methods. The former refreshes all fields and notifyPropertyChanged() updates only the flag of the corresponding BR. The BR is generated with the annotation @bindable, and the view associated with a particular property can be notified with the BR

/** * Author: Ye Yingshi Ye * Time: 2018/5/16 20:54 * Description: */
public class Goods extends BaseObservable {

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

    // Add @bindable annotation to the get method of the member variable if it is private
    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 only this field
        notifyPropertyChanged(com.leavesc.databinding_demo.BR.name);
    }

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

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

    public float getPrice(a) {
        return price;
    }

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

In the setName() method, only this field is updated; in the setDetails() method, all fields are updated

You can see the difference between the two notify methods by adding two buttons to change the three property values of the Goods variable. The button-click event binding involved in this is also covered below


      
<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 the properties name and price"
            android:textAllCaps="false" />

        <Button...android:onClick="@{()->goodsHandler.changeGoodsDetails()}"
            android:text="Change properties Details and Price"
            android:textAllCaps="false" />

    </LinearLayout>
</layout>
Copy the code
/** * Author: Ye Yingshi Ye * Time: 2018/5/16 21:07 * 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(a) {
            goods.setName("code" + new Random().nextInt(100));
            goods.setPrice(new Random().nextInt(100));
        }

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

As you can see, the refresh of the Name view does not refresh the Price view at the same time, while the refresh of the Details view also flushes the Price view

Implements the observables interface class allowed to register a listener, when the property changes of the observed object will notify the listener, OnPropertyChangedCallback them is required at this time

Where propertyId is used to identify the specific field

        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"); }}});Copy the code

ObservableField

Inherits from the Observable class is relatively limited, and notifies are also required, so you can choose to use ObservableField for simplicity. ObservableField can be understood as the official encapsulation of BaseObservable field annotations and refreshes. The official native provides encapsulation of basic data types. For example, ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableD Ouble and ObservableParcelable, and other types can be declared using the ObservableField generic

/** * Author: Ye Yingshi Ye * Time: 2018/5/13 21:33 * 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 = newObservableField<>(details); } ` ` `}Copy the code

Any change to the value of the ObservableGoods property triggers an immediate UI refresh, which is conceptually indistinguishable from an Observable. See the source code below for details

ObservableCollection

DataBinding also provides wrapper classes to replace the native List and Map, ObservableList and ObservableMap, respectively, that refresh the bound view when the data they contain changes


      
<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 the data"/>

    </LinearLayout>
</layout>
Copy the code
	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));
    }
Copy the code

Three, two-way data binding

Bidirectional binding means that the view is refreshed when the data changes, and the data changes when the view changes

Android :text=”@={goods. Name}” Android :text=”@={goods. Name}”


      
<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>
Copy the code
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); }}Copy the code

4. Event binding

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

  • android:onClick
  • android:onLongClick
  • android:afterTextChanged
  • android:onTextChanged
  • .

Create a new UserPresenter class inside the Activity to declare callback methods for the onClick() and afterTextChanged() events

public class UserPresenter {

        public void onUserNameClick(User user) {
            Toast.makeText(Main5Activity.this."Username:" + 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); }}Copy the code

      
<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>
Copy the code

Method references are used in a similar way to function calls. You can choose to keep the signature of the event callback method consistent:@{userPresenter.afterTextChanged}In this case, the method name can be different, but the method parameters and return value must be the same as the original callback function. You can also refer to a function that does not follow the default signature:@{()->userPresenter.onUserNameClick(userInfo)}Lambda expressions are used here so that instead of following the default method signature, theuserInfoObject is returned directly to the click method. In addition, method references can also be used: :For event binding

Use class methods

First define a static method

public class StringUtils {

    public static String toUpperCase(String str) {
        returnstr.toUpperCase(); }}Copy the code

Import the utility class in the data tag

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

It can then be called as 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)}" />
Copy the code

Operator

Base operator

DataBinding supports the use of the following operators, expressions, and keywords in layout files

  • Arithmetic + – / * %
  • String merge +
  • Logic && | |
  • Binary & | ^
  • One yuan + -! ~
  • Shift >> >>> <<
  • Compare == > < >= <=
  • Instanceof
  • Grouping ()
  • character, String, numeric, null
  • Cast
  • The method call
  • Field visit
  • Array access []
  • Three yuan? :

Currently, the following operations are not supported

  • this
  • super
  • new
  • Show generic calls

In addition, DataBinding supports the following types of calls

Null Coalescing

Empty merge operator?? Returns the first value that is not null

 <TextView
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:text="@{user.name ?? user.password}" />
Copy the code

Is equivalent to

	android:text="@{user.name ! = null ? user.name : user.password}"
Copy the code

Attribute control

You can use variable values to control the properties of a View

 <TextView
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:text="Change in visibility"
     android:visibility="@{user.male ? View.VISIBLE : View.GONE}" />
Copy the code

Avoid null pointer exceptions

DataBinding will also automatically help us avoid null pointer exceptions. For example, if userInfo is null in “@{userinfo. password}”, userinfo. password will be assigned to the default value null without throwing a null pointer exception

Include and viewStub

include

For include layout files, you need to use the layout tag to declare the variables that need to be used in the included layout

view_include.xml


      
<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>
Copy the code

The two layout files share the same variable by passing the corresponding variable to the include layout in the main layout file


      
<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>
Copy the code

viewStub

DataBinding also supports ViewStub layouts

Reference the viewStub layout in the layout file

   <ViewStub
        android:id="@+id/view_stub"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout="@layout/view_stub"/>
Copy the code

Gets the ViewStub object, and thus controls the visibility of the ViewStub

	ActivityMain6Binding activityMain6Binding = DataBindingUtil.setContentView(this, R.layout.activity_main6);
	View view = activityMain6Binding.viewStub.getViewStub().inflate();
Copy the code

If variable values need to be bound to the ViewStub, the ViewStub file is also laid out using the Layout label. The main layout file uses the custom bind namespace to pass variables to the 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}" />
Copy the code

If you do not use bind:userInfo=”@{userInf}” to data bind the ViewStub in your XML, you can wait until the ViewStub Inflate variable, You need to set the setOnInflateListener callback function for the ViewStub, and do the data binding in the 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 data bind the viewStub in XML
                // Then you can do manual binding here
                ViewStubBinding viewStubBinding = DataBindingUtil.bind(inflated);
                viewStubBinding.setUserInfo(user);
                Log.e(TAG, "onInflate"); }});Copy the code

Eight, BindingAdapter

The dataBinding provides a BindingAdapter annotation to support custom properties, or to modify existing properties. The value can be an existing XML attribute, such as Android: SRC, Android :text, etc., or you can customize the attribute and use it in XML

For example, for an ImageView, if you want to dynamically change the displayed image when the value of a variable changes, you can do so using a BindingAdapter

We need to define a static method and add a BindingAdapter annotation to it. The annotation value is the name of the custom property for the ImageView control. The two parameters of the static method can be interpreted as follows: When the value of the ImageView control’s URL property changes, the dataBinding passes the ImageView instance and the new URL value to the loadImage() method, where the dataBinding dynamically changes the ImageView properties

    @BindingAdapter({"url"})
    public static void loadImage(ImageView view, String url) {
        Log.e(TAG, "loadImage url : " + url);
    }
Copy the code

Associate variable values in XML files, where the name bind can be customized


      
<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>
Copy the code

One of the more powerful aspects of BindingAdapter is the ability to override Android’s original control properties. For example, you can assign a suffix to the text of each Button: “-button”

    @BindingAdapter("android:text")
    public static void setText(Button view, String text) {
        view.setText(text + "-Button");
    }
Copy the code
    <Button
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:onClick="@{()->handler.onClick(image)}"
       android:text='@{" change image Url"}'/>
Copy the code

As a result, controls that use the “Android :text” attribute throughout the project will display text with an extra suffix

Nine, BindingConversion

DataBinding also supports conversion of data, or type conversion

Similar to BindingAdapter, the following method adds the -conversionString suffix to all String variables referenced in @{String} in the layout file

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

The XML file

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text='@{"xxx"}'
            android:textAllCaps="false"/>
Copy the code

As you can see, for the Button, both BindingAdapter and BindingConversion are in effect, with BindingConversion having a higher priority

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

If you look at the layout below, when you assign values to the background and textColor properties, you use strings, which would normally cause an error. But with BindingConversion you can automatically convert the string type value to the required Drawable and Color

	    <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background='@ {" red "}'
            android:padding="20dp"
            android:text="Blue letters on a 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 letters on a blue background."
            android:textColor='@ {" red "}'/>
Copy the code
	@BindingConversion
    public static Drawable convertStringToDrawable(String str) {
        if (str.equals("Red")) {
            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("Red")) {
            return Color.parseColor("#FF4081");
        }
        if (str.equals("Blue")) {
            return Color.parseColor("#3F51B5");
        }
        return Color.parseColor("# 344567");
    }
Copy the code

Array, List, Set, Map…

DataBinding also supports the use of arrays, lsits, sets, and maps in layout files, all of which can be retrieved in the form of lists [index]

To distinguish it from the Angle brackets of the variable tag, you need to use the Angle brackets escape characters when declaring data types such as Lsit< String >


      
<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>
Copy the code

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>
Copy the code

strings.xml

    <string name="format">%s is %s</string>
Copy the code
    <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" />
Copy the code

This is the end of the introduction to DataBinding. Of course, there are some loose ends, but in general I think I’ve covered them, and I’ll leave the rest for later

The above sample code is available for download here, or can you give a Star on GitHub?

Project home page -> DataBinding_Demo