跳转至

Using data binding in Android

This tutorial describes the usage of data binding in Android applications. Data binding allows to synchronize your user interface with your application model and logic.

1. Using data binding in Android applications

1.1. Introduction to data binding in Android

Android offers support to write declarative layouts using data binding. This minimizes the necessary code in your application logic to connect to the user interface elements.

The usage of data binding requires changes in your layout files. Such layout files starts with a layout root tag followed by a data element and a view root element. The data elements describe data which is available for binding. This view element contains your root hierarchy similar to layout files which are not used with data binding. References to the data elements or expressions within the layout are written in the attribute properties using the @{} or @={},

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="temp" type="com.vogella.android.databinding.TemperatureData"/> **(1)**
   </data>
   <LinearLayout **(2)**
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{temp.location}"/>
       <TextView
        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@{temp.celsius}"/>
   </LinearLayout>
</layout>
  • 1 The user variable within data describes a property that may be used within this layout.
  • 2 Normal view hierarchy

Android data binding generates a Binding class based on this layout. This class holds all the bindings from the layout properties, i.e., the defined variable to the corresponding views. It also provides generated setters for your data elements from the layout. The name of the generated class is based on the name of the layout file. This name is converted to Pascal case and the Binding suffix is added to it. For example, if the layout file is called activity_main.xml, the generate class is called ActivityMainBinding. You can inflate the layout and connect your model via this class or the DataBindingUtil class.

TemperatureData temperatureData = // your data is created here
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setTemp(temperatureData); // generated setter based on the data in the layout file

You can use the inflate method on the generated class. This is useful for using data binding in fragments, ListView or RecyclerView.

ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater(), container, attachToContainer);
// get the root view
View view = binding.getRoot();
// do more stuff
TemperatureData temperatureData = // your data is created here
binding.setTemp(temperatureData); // generated setter based on the data in the layout file

You can also inflate layouts for RecyclerView, ViewPager, or other things that aren’t setting the Activity contents.

1.2. Enable data binding in your Android application

To enable the usage of data binding in your Android application, add the following snippet to the app/build.gradle file.

android {
    ....
    dataBinding {
        enabled = true
    }
}

1.3. Data binding for events via listener bindings and method references

Events may be bound to handler methods directly, similar to the way android:onClick can be assigned to a method in the activity. Event attribute names are governed by the name of the listener method with a few exceptions. For example, View.OnLongClickListener has a method onLongClick(), so the attribute for this event is android:onLongClick.

To assign an event to its handler, use a normal binding expression, with the value being the method name to call. The binding expression can assign the click listener for a View.

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

    <data>
        <variable
            name="presenter"
            type="com.vogella.android.databinding.MainActivityPresenter"/>
    </data>


    <Button
            android:text="Start second activity"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{() -> presenter.showList()}"
            />

</layout>

You could also bind to a method reference via android:onClick="@{handlers::onClickFriend}"/>. If you methods need parameters, you can also pass your data object to them. For example:

android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"

1.4. Imports

You can also import classes to use them in your data binding expressions.

<data>
    <import type="com.example.MyStringUtils"/>
    <variable name="user" type="com.example.User"/>
</data>

<TextView
   android:text="@{MyStringUtils.capitalize(user.lastName)}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

1.5. Updating the user interfaces with changes from the data model

Any plain old Java object (POJO) can be used for data binding. But if updates in the data model should also update the user interface, the objects must be able to notify about data changes. There are three different data change notification mechanisms: * observable objects * observable fields * observable collections

Android provides the BaseObservable class which you can extend. The data class is responsible for notifying when the properties change. This is done by assigning a @Bindable annotation to the getter and notifying in the setter.

package com.vogella.android.databinding;


import android.databinding.BaseObservable;
import android.databinding.Bindable;

import java.util.Observable;

public class TemperatureData extends BaseObservable {
    private String celsius;

    public TemperatureData(String celsius) {
        this.celsius = celsius;
    }

    @Bindable                            **(1)**
    public String getCelsius() {
        return celsius;
    }

    public void setCelsius(String celsius) {
        this.celsius = celsius;
        notifyPropertyChanged(BR.celsius);         **(2)**
    }
}
  • 1 Define a relevant getter
  • 2 Notify any listeners, BR.celsius is a generated class

This listener is invoked on every update and it updates the corresponding views. This ensures that updates in the model updates also the UI.

Alternatively to create a observable class, you can also use ObservableField and its subclass for properties.

private class TemperatureData {
   public final ObservableField<String> celsius = new ObservableField<>();
   public final ObservableField<String> location =  new ObservableField<>();
}

To access such fields in your code, use the set and get methods.

temp.location.set("Hamburg");
String celsius  = temp.celsius.get();

1.6. Custom converters with BindingAdapter

Sometimes you have to perform complex data conversions. For this, you can register a custom converter via the static @BindingAdapter method. This method can be placed anywhere in your code and can override the default conversion of a field to your data model.

For example, assume that you want to assign a field of your data model to an image view.

  <ImageView
            android:id="@+id/icon"
            android:layout_width="40dp"
            android:layout_height="fill_parent"
            android:layout_alignParentBottom="true"
            android:layout_alignParentTop="true"
            android:layout_marginRight="6dip"
            android:contentDescription="TODO"
            android:src="@{obj.url}"
            />

You can register for this property on ImageView with the following method. This method uses Glide to download the image.

@BindingAdapter("android:src")
    public static void setImageUrl(ImageView view, String url) {
        Glide.with(view.getContext()).load(url).into(view);
    }

googletag.cmd.push(function() { googletag.display('ad-inBetween01'); });

2. Exercise: Using data binding in Android applications

In this exercise you learn how to interact between your user interface widgets using data binding. Create a new Android application for this exercise, with the com.vogella.android.databinding top level package. Use the Empty template for this purpose.

2.1. Activate the usage of data binding

Open your app/build.gradle file and activate the usage of data binding.

apply plugin: 'com.android.application'

android {

    dataBinding {
        enabled = true
    }

    .... [REST AS BEFORE...]
  • Ensure you pick the correct build file.
  • This setting must be done in the build.gradle file of your app.

2.2. Create classes for the view interaction

Create the following classes.

package com.vogella.android.databinding;


import android.databinding.BaseObservable;
import android.databinding.Bindable;

public class TemperatureData extends BaseObservable {
    private String location;
    private String celsius;

    public TemperatureData(String location, String celsius) {
        this.location = location;
        this.celsius = celsius;
    }

    @Bindable
    public String getCelsius() {
        return celsius;
    }

    @Bindable
    public String getLocation() {
        return location;
    }

    public  void setLocation(String location){
        this.location = location;
        notifyPropertyChanged(BR.location);
    }

    public void setCelsius(String celsius) {
        this.celsius = celsius;
        notifyPropertyChanged(BR.celsius);
    }

}
  • The BR class is not yet generated.
  • After the definition of the layout file, the is will be generated by the Gradle tooling.
package com.vogella.android.databinding;


public interface MainActivityContract {
    public interface Presenter {
        void onShowData(TemperatureData temperatureData);
    }

    public interface View {
        void showData(TemperatureData temperatureData);
    }

}
package com.vogella.android.databinding;

import android.content.Context;

public class MainActivityPresenter implements MainActivityContract.Presenter {
    private MainActivityContract.View view;
    private Context ctx;

    public MainActivityPresenter(MainActivityContract.View view, Context ctx) {
        this.view = view;
        this.ctx = ctx;
    }

    @Override
    public void onShowData(TemperatureData temperatureData) {
        view.showData(temperatureData);
    }

}

2.3. Adjust layout file and activity to use data binding

Change the layout to the following.

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

    <data>
        <variable
            name="temp"
            type="com.vogella.android.databinding.TemperatureData" />
        <variable
            name="presenter"
            type="com.vogella.android.databinding.MainActivityPresenter"/>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={temp.location}"
            />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={temp.celsius}"
            />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:text="@={temp.celsius}" />

        <Button
            android:text="Show data model"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{() -> presenter.onShowData(temp)}"
            android:id="@+id/button" />

    </LinearLayout>
</layout>
  • You see some warning messages in the editor, e.g., because you used hard-codes strings.
  • For this exercise, we ignore these warnings.

Adjust your activity code to use the generated data binding classes.

package com.vogella.android.databinding;

import android.app.Activity;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.widget.Toast;

import com.vogella.android.databinding.databinding.ActivityMainBinding;

public class MainActivity extends Activity implements MainActivityContract.View {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        MainActivityPresenter mainActivityPresenter = new MainActivityPresenter(this, getApplicationContext());
        TemperatureData temperatureData = new TemperatureData("Hamburg", "10");
        binding.setTemp(temperatureData);
        binding.setPresenter(mainActivityPresenter);
    }

    @Override
    public void showData(TemperatureData temperatureData) {
        String celsius = temperatureData.getCelsius();
        Toast.makeText(this, celsius, Toast.LENGTH_SHORT).show();
    }

}

2.4. Convince Android Studio to compile your application

If the BR class is missing, select Build  Clean followed by Build  Make Project.

2.5. Validate your application

Start your application. If you press the button, a small popup should be shown with the correct data.

The first text view should The second TextView should update automatically, if you type in the EditText field.

3. Exercise: Using data binding for RecyclerView

In this exercise you learn how to use data binding for a recyclerview. Continue to use the com.vogella.android.databinding package.

3.1. Define a new activity and allow to start it

Create a new activity called SecondActivity. Ensure that you add it to your Android manifest.

Adjust your MVP contract to start the second activity.

package com.vogella.android.databinding;


public interface MainActivityContract {
    public interface Presenter {
        void onShowData(TemperatureData temperatureData);
        void showList();
    }

    public interface View {
        void showData(TemperatureData temperatureData);
    }

}

Implement this new behavior in MainActivityPresenter to start the second activity.

package com.vogella.android.databinding;

import android.content.Context;
import android.content.Intent;

public class MainActivityPresenter implements MainActivityContract.Presenter {

    private MainActivityContract.View view;
    private Context ctx;


    public MainActivityPresenter(MainActivityContract.View view, Context ctx) {
        this.view = view;
        this.ctx = ctx;
    }


    @Override
    public void onShowData(TemperatureData temperatureData) {
        view.showData(temperatureData);
    }

    @Override
    public void showList() {
        Intent i = new Intent(ctx, SecondActivity.class);
        ctx.startActivity(i);
    }
}

3.2. Adjust layout file and activity to use data binding

Change the layout to the following.

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

    <data>
        <variable
            name="temp"
            type="com.vogella.android.databinding.TemperatureData" />
        <variable
            name="presenter"
            type="com.vogella.android.databinding.MainActivityPresenter"/>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={temp.location}"
            />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={temp.celsius}"
            />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:text="@={temp.celsius}" />

        <Button
            android:text="Show data model"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{() -> presenter.onShowData(temp)}"
            android:id="@+id/button" />

        <Button
            android:text="Start second activity"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{() -> presenter.showList()}"
            />

    </LinearLayout>
</layout>

3.3. Add dependency to RecyclerView

Open your app/build.gradle file and add the dependency to recyclerview.

dependencies {
    // more
    compile "com.android.support:recyclerview-v7:25.1.1"
}
  • Ensure you pick the correct build file.
  • You need to update the app build file.

3.4. Create icon

Add an ic_listentry icon to your application.

3.5. Implement the Recyclerview with data binding.

Create the following layout called activity_second.xml.

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

    <data>
        <variable
            name="temp"
            type="com.vogella.android.databinding.TemperatureData" />
        <variable
            name="presenter"
            type="com.vogella.android.databinding.MainActivityPresenter"/>
    </data>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical" />
</layout>

Create the following layout called rowlayout.xml.

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

    <data>

        <variable
            name="obj"
            type="com.vogella.android.databinding.TemperatureData"
            />
    </data>

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="?android:attr/listPreferredItemHeight"
        android:padding="6dip"
        >

        <ImageView
            android:id="@+id/icon"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_alignParentBottom="true"
            android:layout_alignParentTop="true"
            android:layout_marginRight="6dip"
            android:contentDescription="TODO"
            android:src="@drawable/ic_listentry"
            />

        <TextView
            android:id="@+id/secondLine"
            android:layout_width="fill_parent"
            android:layout_height="26dip"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_toRightOf="@id/icon"
            android:ellipsize="marquee"
            android:text="@{obj.location}"
            android:textSize="12sp"
            android:maxLines="1"
        />

        <TextView
            android:id="@+id/firstLine"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_above="@id/secondLine"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:layout_alignWithParentIfMissing="true"
            android:layout_toRightOf="@id/icon"
            android:gravity="center_vertical"
            android:text="@{obj.celsius}"
            android:textSize="16sp"
            />

    </RelativeLayout>

</layout>

Create the following adapter.

package com.vogella.android.databinding;

import android.databinding.DataBindingUtil;
import android.databinding.ViewDataBinding;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;

import com.vogella.android.databinding.databinding.RowlayoutBinding;

import java.util.List;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
        private List<TemperatureData> data;

        // Provide a reference to the views for each data item
        // Complex data items may need more than one view per item, and
        // you provide access to all the views for a data item in a view holder
        public class MyViewHolder extends RecyclerView.ViewHolder {
                // each data item is just a string in this case
                private final ViewDataBinding binding;

                public MyViewHolder(ViewDataBinding binding) {
                        super(binding.getRoot());
                        this.binding = binding;
                }
                public void bind(Object obj) {
                       binding.setVariable(BR.obj,obj);
                       binding.executePendingBindings();
                }
        }

        // Provide a suitable constructor (depends on the kind of dataset)
        public MyAdapter(List<TemperatureData> myDataset) {
                data = myDataset;
        }

        // Create new views (invoked by the layout manager)
        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                // create a new view
                LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
                ViewDataBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.rowlayout, parent, false);
                // set the view's size, margins, paddings and layout parameters
                return new MyViewHolder(binding);
        }

        // Replace the contents of a view (invoked by the layout manager)
        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
                final TemperatureData temperatureData = data.get(position);
                holder.bind(temperatureData);

        }

        // Return the size of your dataset (invoked by the layout manager)
        @Override
        public int getItemCount() {
            return data.size();
        }

}

Update your SecondActivity class.

package com.vogella.android.databinding;

import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import java.util.Arrays;
import java.util.List;

public class SecondActivity extends Activity  {

    private RecyclerView recyclerView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager layoutManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

        // use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        recyclerView.setHasFixedSize(true);

        // use a linear layout manager
        layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);

        List<TemperatureData> items =
                Arrays.asList(new TemperatureData("Hamburg", "5"), new TemperatureData("Berlin", "6"));

        // define an adapter
        mAdapter = new MyAdapter(items);
        recyclerView.setAdapter(mAdapter);
    }
}

3.6. Validate your application

Start your application and navigate to your second activity. Ensure the list is correctly displayed.

3.7. Optional exercise: Create an abstract class for your adapter

Most of code in adapter can be the same if data binding is used. The only requirement is that the object name in the layout file is the same, so that the generated entry in the BR class is the same. In our example we use obj for it.

To reuse most of our adapter, create an abstract class with the logic to bind to any object.

package com.vogella.android.databinding;

import android.databinding.DataBindingUtil;
import android.databinding.ViewDataBinding;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;

import com.vogella.android.databinding.databinding.RowlayoutBinding;

public abstract class MyBaseAdapter extends RecyclerView.Adapter<MyBaseAdapter.MyViewHolder> {

        // Provide a reference to the views for each data item
        // Complex data items may need more than one view per item, and
        // you provide access to all the views for a data item in a view holder
        public class MyViewHolder extends RecyclerView.ViewHolder {
                // each data item is just a string in this case
                private final ViewDataBinding binding;

                public MyViewHolder(ViewDataBinding binding) {
                        super(binding.getRoot());
                        this.binding = binding;
                }
                public void bind(Object obj) {
                       binding.setVariable(BR.obj,obj);
                       binding.executePendingBindings();
                }
        }

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                // create a new view
                LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
                ViewDataBinding binding = DataBindingUtil.inflate(layoutInflater, getLayoutIdForType(viewType), parent, false);
                // set the view's size, margins, paddings and layout parameters
                return new MyViewHolder(binding);
        }

        // Replace the contents of a view (invoked by the layout manager)
        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
                holder.bind(getDataAtPosition(position));
        }



        public abstract Object getDataAtPosition(int position);

        public abstract int getLayoutIdForType(int viewType);

}

Now you can adjust your existing adapter to extend the MyBaseAdapter.

package com.vogella.android.databinding;

import java.util.List;

public class MyAdapter extends MyBaseAdapter {

    List<TemperatureData> data;

    // Provide a suitable constructor (depends on the kind of dataset)
    public MyAdapter(List<TemperatureData> myDataset) {
        data = myDataset;
    }
    @Override
    public Object getDataAtPosition(int position) {
        return data.get(position);
    }

    @Override
    public int getLayoutIdForType(int viewType) {
        return R.layout.rowlayout;
    }

    @Override
    public int getItemCount() {
        return data.size();
    }
}
  • Having this base adapter allows you to reuse lots of code for new adapter implementations.

3.8. Optional exercise: Use a custom converter

Add a field url to your data model and use Glide to download such an image. Examples URLs for images can be found on http://lorempixel.com/.

Add the following dependency to your app/build.gradle file.

compile 'com.github.bumptech.glide:glide:3.6.1'

To allow Glide to download from the Internet, add the permission to use the Internet to your manifest.

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

To register a custom converter, define the following static method, either in your activity or in a separate class.

@BindingAdapter("android:src")
    public static void setImageUrl(ImageView view, String url) {
        Glide.with(view.getContext()).
            load(url).
            placeholder(R.drawable.ic_listentry).
        into(view);
    }

Now change your data model.

package com.vogella.android.databinding;

import android.databinding.BaseObservable;
import android.databinding.Bindable;

public class TemperatureData extends BaseObservable {

    private String location;

    private String celsius;

    private String url;

    public TemperatureData(String location, String celsius, String url) {
        this.location = location;
        this.celsius = celsius;
        this.url = url;
    }

    @Bindable
    public String getCelsius() {
        return celsius;
    }

    @Bindable
    public String getLocation() {
        return location;
    }

    @Bindable
    public String getUrl() {
        return url;
    }


    public void setLocation(String location) {
        this.location = location;
        notifyPropertyChanged(BR.location);
    }

    public void setCelsius(String celsius) {
        this.celsius = celsius;
        notifyPropertyChanged(BR.celsius);
    }

    public void setUrl(String url) {
        this.url = url;
        notifyPropertyChanged(BR.url);
    }
}

Also adjust the construction of the data model elements. For example, for the list.

List<TemperatureData> items =
    Arrays.asList(
        new TemperatureData("Hamburg", "5", "http://lorempixel.com/40/40/"),
        new TemperatureData("Berlin", "6","http://lorempixel.com/40/40/"));

Adjust the android.src attribute in your rowlayout.xml.

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

    <data>

        <variable
            name="obj"
            type="com.vogella.android.databinding.TemperatureData"
            />
    </data>

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="?android:attr/listPreferredItemHeight"
        android:padding="6dip"
        >

        <ImageView
            android:id="@+id/icon"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_alignParentBottom="true"
            android:layout_alignParentTop="true"
            android:layout_marginRight="6dip"
            android:contentDescription="TODO"
            android:src="@{obj.url}"
            />

        <TextView
            android:id="@+id/secondLine"
            android:layout_width="fill_parent"
            android:layout_height="26dip"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_toRightOf="@id/icon"
            android:ellipsize="marquee"
            android:text="@{obj.location}"
            android:textSize="12sp"
            android:maxLines="1"
        />

        <TextView
            android:id="@+id/firstLine"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_above="@id/secondLine"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:layout_alignWithParentIfMissing="true"
            android:layout_toRightOf="@id/icon"
            android:gravity="center_vertical"
            android:text="@{obj.celsius}"
            android:textSize="16sp"
            />

    </RelativeLayout>

</layout>

googletag.cmd.push(function() { googletag.display('ad-afterResources'); });

4. Android databinding resources

Androids Data Binding Library

Blog about about custom setters in Data binding

George Mount about Data Binding and RecyclerView

Dynamic view generation with Data Binding

Video introduction into Data Binding

原文链接: https://www.vogella.com/tutorials/AndroidDatabinding/article.html