3: 08: Android DataBinding from entry to advanced

Data binding is a framework officially released by Google. As the name implies, 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. MVVM, as opposed to MVP, actually replaces the Presenter layer with the ViewModel layer. DataBinding can save the findViewById() step we have been doing, greatly reduce the code in the Activity, and data can be bound to the layout file in one way or two ways, which helps prevent memory leakage, and can automatically detect null to avoid null pointer exceptions

The method to enable DataBinding is based on the build.gradle Add the following code to the file, and support for DataBinding can be introduced after synchronization

android {
    dataBinding {
        enabled = true
    }
}

1, Basic introduction

After enabling DataBinding, let's see 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 by 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 between the original layout and 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 realize MVVM's ViewModel, it needs to bind the data (Model) to the UI (View). The data tag functions as a bridge to build the channel between View and Model

Let's first declare a modal

package com.leavesc.databinding_demo.model;

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 you don't have to specify the entire package name path every time java.lang The classes in the. * package will be imported automatically, so you can use it 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, you can use alias 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>

A User type variable userInfo is declared here. What we need to do is to hook this variable with two TextView controls. By setting the variable value of userInfo, TextView will display the corresponding text at the same time
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>

Through@{ userInfo.name }Make TextView reference to the relevant variable, and DataBinding will map it to the corresponding getter method
After that, you can set the layout file through DataBindingUtil in 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 }There is no clear value in the layout file, so nothing will be displayed in the preview view, which is not convenient to observe the text size, font color and other attributes. At this time, you can set the default value (text content or font size and other attributes 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 get the control with the specified ID directly 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, which will be changed to the hump naming method of initial capitalization, and the underline contained in the layout file name will be omitted. Control is obtained in a similar way, but with a lowercase initial

You can also customize the instance name of ViewDataBinding as follows

    <data class="CustomBinding">

    </data>

In addition, a special variable named context will be generated in the binding expression as needed. 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 that name

Databinding is also supported in Fragment and RecyclerView. For example, you can see the use of databinding 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 way of data binding, whenever the bound variables change, you need to re pass new variable values to ViewDataBinding to refresh the UI. Next, let's see how to automatically refresh the UI**

2, One way data binding

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

BaseObservable

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

BaseObservable provides two methods, notifyChange() and notifyPropertyChanged(). The former will refresh all value fields, while the latter will only update the flag of the corresponding br. The generation of BR is generated by annotation @ Bindable, which can be associated with views of specific attributes through BR notify

/**
 * Author: leaves should be leaves
 * 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 @ Bindable annotation on the get method of 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;
    }

}

This field is the only one updated in the setName() method, while all fields are updated in the setDetails() method

You can see the difference between the two notify methods by adding two buttons to change the three attribute values of the goods variable. The button click event binding involved is also 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: leaves should be leaves
 * 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));
        }

    }

}

It can be seen that the refresh of name view does not refresh the price view at the same time, while the refresh of details view also refreshes the price view

 

The class that implements the Observable interface allows you to register a listener. When the property of the Observable object changes, the listener will be notified. In this case, OnPropertyChangedCallback is needed

The 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 limited and requires a notify operation, so you can choose to use the ObservableField for simplicity. The ObservableField can be understood as the official encapsulation of the annotation and refresh operations of the fields in the BaseObservable. The official native provides encapsulation of the basic data types, such as ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble and ObservableParcelable, which can also be realized through the ObservableField generics to declare other types

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);
    }

    ```
}

Changes to the value of the ObservableGoods property will immediately trigger a UI refresh. Conceptually, it is not different from Observable. For the specific effect, see the source code provided below, which will not be discussed here

ObservableCollection

dataBinding also provides a wrapper class to replace the native List and Map, which are ObservableList and ObservableMap. When the data contained in them changes, the bound view will refresh accordingly

<?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));
    }

3, Two way data binding

The meaning of bi-directional binding is to refresh the view when the data changes, and change the data when the view changes

See the following example. When the input content of EditText changes, it will be synchronized to the variable goods at the same time. The way to bind variables is one more equal sign 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);
    }

}

4, Event binding

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

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

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

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>

Method reference is similar to function call. You can choose to keep the signature of event callback method consistent@{ userPresenter.afterTextChanged }At this time, the method name can be different, but the method parameter and return value must be consistent with the original callback function. You can also refer to functions that do not follow the default signature: @ {() - > userPresenter.onUserNameClick (userInfo)}, the Lambda expression is used here, so that the userInfo object can be directly returned to the click method without following the default method signature. In addition, you can use method reference:: to bind events

5, Using class methods

First define a static method

public class StringUtils {

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

}

Import the tool class in the data tag

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

And then it can be called 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, Operators

Basic operator

DataBinding supports 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
  • Method call
  • Field access
  • Array access []
  • Three yuan:

The following operations are not supported at this time

  • this
  • super
  • new
  • Show generic calls

In addition, DataBinding supports the following forms of calls

Null Coalescing

Null merge operator - takes the first non null value 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

View properties can be controlled by variable values

 

 <TextView
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:text="Visibility changes"
     android:visibility="@{user.male  ? View.VISIBLE : View.GONE}" />

Avoid null pointer exceptions

DataBinding also automatically helps us avoid null pointer exceptions
For example, if "@{ userInfo.password }"If userinfo is null in, userInfo.password Will be assigned the default value of null without throwing a null pointer exception

7, include and viewStub

include

For the included layout file, it also supports data binding through dataBinding. At this time, it is also necessary to use the layout tag in the layout to be included and 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>

The corresponding variables are passed to the include layout in the main layout file, so that the same variables are shared between the 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 also supports ViewStub layout

Reference viewStub layout in layout file

 

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

Gets the ViewStub object so that you can control the visibility of the ViewStub

 

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

If you need to bind variable values for the ViewStub, the ViewStub file uses the layout label for layout, and 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}" />

If not used in xml bind:userInfo="@{userInf}" performs data binding on the ViewStub. You can wait until the ViewStub is inflamed before binding variables. At this time, you need to set setOnInflateListener callback function for the ViewStub to perform data binding in the callback function

 

        activityMain6Binding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
            @Override
            public void onInflate(ViewStub stub, View inflated) {
                //If not used in xml bind:userInfo= '@ {userinf}' data bound to viewStub
                //Then you can bind manually here
                ViewStubBinding viewStubBinding = DataBindingUtil.bind(inflated);
                viewStubBinding.setUserInfo(user);
                Log.e(TAG, "onInflate");
            }
        });

8, BindingAdapter

dataBinding provides the BindingAdapter annotation to support custom properties or modify existing properties. The annotation value can be an existing xml attribute, such as android:src , android:text You can also customize attributes and use them in xml

For example, for an ImageView, when the value of a variable changes, we want to dynamically change the displayed image. At this time, we can use the BindingAdapter to achieve this

A static method needs to be defined first to add a BindingAdapter annotation. The annotation value is the property name customized for the ImageView control. The two parameters of the static method can be understood as follows: when the url property value of the ImageView control changes, dataBinding will pass the ImageView instance and the new url value to loadImage() Method so that the relevant properties of ImageView can be changed dynamically here

 

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

In the xml file, associate the variable value, in which the name bind 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>

One of the more powerful features of BindingAdapter is that it can override the original control properties of Android. For example, you can set the suffix to be added to the text of each Button: "- 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 "For the control of this property, the displayed text will have an extra suffix

9, BindingConversion

dataBinding also supports data conversion or type conversion

Similar to the BindingAdapter, the following method will add the suffix - conversionString to all String type variables in the layout file that are referenced as @ {String}

 

    @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"/>

As you can see, for the Button, the BindingAdapter and BindingConversion are in effect at the same time, and the priority of BindingConversion is higher

In addition, BindingConversion can be used to convert the type of property values

Look at the following layout. When assigning values to the background and textColor attributes, strings are used directly. Normally, errors will be reported. However, with BindingConversion, values of string type can be automatically converted to the desired Drawable and Color

 

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background='@{"gules"}'
            android:padding="20dp"
            android:text="Red background blue words"
            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="Blue background red characters"
            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");
    }

10, Array, List, Set, Map

dataBinding also supports the use of arrays, lsits, sets, and maps in layout files, and the elements can be obtained in the form of list[index] in layout files

In order to distinguish it from the angle bracket of variable label, the escape character of angle bracket is needed when declaring data type such as LSIT < string >

 

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

The introduction of DataBinding will be over here. Of course, there must be some lost knowledge points, but in general, I think I have made it clear, and the rest will be added later

Author: ye Zhichen
 Link: https://www.jianshu.com/p/bd9016418af2
 Source: Jianshu
 The copyright belongs to the author. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source.


 

 

Tags: Android xml encoding Java

Posted on Tue, 23 Jun 2020 23:49:02 -0400 by gusaps