ZOFTINO.COM android and web dev tutorials

Android RecyclerView Data Binding Example

In this post, you can learn how to use data binding library to bind event handler and data model object properties to views in the item layout of RecyclerView. Using data binding for RecyclerView, you don’t need to use findViewById in ViewHolders and set properties of item data object to the attributes of views, data binding takes care of it.

Please read data binding library tutorial to know more about projects setup, data binding concepts and examples.

The example to show how to use data binding with RecyclerView displays list of flights in RecyclerView, blow is the screen shot, followed by that is explanation about how data binding is used in recycler view adapter and then you can find complete code.

android databinding recyclerview example

First create item layout declaring item object as data binding variable, then bind properties of the item object to attributes of Views in the item layout using data binding expression.

<?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>
        <variable name="flight" type="zoftino.com.databinding.Flight"/>
        <variable name="itemClickListener"
            type="zoftino.com.databinding.FlightsRecyclerViewAdapter.ViewHolder"/>
    </data>
    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        tools:context="zoftino.com.databinding.FlightsActivity">
        <TextView
            android:id="@+id/air_lines"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{flight.airLines}"
            android:textAppearance="@style/TextAppearance.AppCompat.Headline"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
	..... 

In recycler view adapter’s onCreateViewHolder method, get data binding object using DataBindingUtil and instantiate ViewHolder object passing data binding object to its constructor.

 @Override
public FlightsRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                               int viewType) {
    FlightItemLayoutBinding binding = DataBindingUtil.inflate(
            LayoutInflater.from(parent.getContext()),
            R.layout.flight_item_layout, parent, false);

    ViewHolder viewHolder = new ViewHolder(binding);
    return viewHolder;
}
 

In recycler view adapter’s onBindViewHolder method, set item object and item click listener on binding object that view holder contains.

 @Override
public void onBindViewHolder(ViewHolder holder, int position) {
    Flight flight = flightsList.get(position);
    holder.flightItemBinding.setFlight(flight);
    holder.flightItemBinding.setItemClickListener(this);
}
 

Activity

import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;

import java.util.ArrayList;
import java.util.List;

import zoftino.com.databinding.databinding.ActivityFlightsBinding;

public class FlightsActivity extends AppCompatActivity{
   private FlightsRecyclerViewAdapter adapter;
    private ActivityFlightsBinding binding;

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

        binding = DataBindingUtil.setContentView(this, R.layout.activity_flights);
        binding.flightsRv.setLayoutManager(new LinearLayoutManager(this));
        binding.flightsRv.addItemDecoration(
                new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));

        FlightsRecyclerViewAdapter adapter =
                new FlightsRecyclerViewAdapter(prepareData(), this);
        binding.flightsRv.setAdapter(adapter);

    }

    public List<Flight> prepareData(){
        List<Flight> flights = new ArrayList<>();

        Flight flight = new Flight("Delta", "Seattle", "London", "10:20", "17:30", "$388");
        flights.add(flight);
        flight = new Flight("Virgin Atlantic", "Seattle", "London", "10:20", "17:30", "$330");
        flights.add(flight);
        flight = new Flight("American Airlines", "Seattle", "London", "10:20", "17:30", "$400");
        flights.add(flight);
        flight = new Flight("British Airways", "Seattle", "London", "10:20", "17:30", "$440");
        flights.add(flight);
        flight = new Flight("Quatar Airways", "Seattle", "London", "10:20", "17:30", "$300");
        flights.add(flight);
        flight = new Flight("KLM", "Seattle", "London", "10:20", "17:30", "$350");
        flights.add(flight);
        flight = new Flight("Emirates", "Seattle", "London", "10:20", "17:30", "$420");
        flights.add(flight);
        flight = new Flight("Lufthansa","Seattle", "London", "10:20", "17:30", "$390");
        flights.add(flight);
        flight = new Flight("Air India", "Seattle", "London", "10:20", "17:30", "$350");
        flights.add(flight);
        flight = new Flight("Jet Airways", "Seattle", "London", "10:20", "17:30", "$390");
        flights.add(flight);
        flight = new Flight("United", "Seattle", "London", "10:20", "17:30", "$3450");
        flights.add(flight);
        flight = new Flight("Air Canada","Seattle", "London", "10:20", "17:30", "$398");
        flights.add(flight);

        return flights;
    }
}

Activity Layout

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/flights_rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"/>
</LinearLayout>
</layout>

Item Layout

<?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>
        <variable name="flight" type="zoftino.com.databinding.Flight"/>
        <variable name="itemClickListener"
            type="zoftino.com.databinding.FlightsEventListener"/>
    </data>
    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        tools:context="zoftino.com.databinding.FlightsActivity">
        <TextView
            android:id="@+id/air_lines"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{flight.airLines}"
            android:textAppearance="@style/TextAppearance.AppCompat.Headline"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
        <TextView
            android:id="@+id/from_location"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="4dp"
            android:text="@{flight.fromLocation}"
            app:layout_constraintTop_toBottomOf="@+id/air_lines"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toLeftOf="@+id/to_location"/>
        <TextView
            android:id="@+id/to_location"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="4dp"
            android:text="@{flight.toLocation}"
            app:layout_constraintBaseline_toBaselineOf="@+id/from_location"
            app:layout_constraintLeft_toRightOf="@+id/from_location"
            app:layout_constraintRight_toRightOf="parent"/>
        <TextView
            android:id="@+id/start_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{flight.startTime}"
            app:layout_constraintTop_toBottomOf="@+id/from_location"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toLeftOf="@+id/reach_time"/>
        <TextView
            android:id="@+id/reach_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{flight.reachTime}"
            app:layout_constraintBaseline_toBaselineOf="@+id/start_time"
            app:layout_constraintLeft_toRightOf="@+id/start_time"
            app:layout_constraintRight_toRightOf="parent"/>
        <TextView
            android:id="@+id/cost"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:text="@{flight.cost}"
            app:layout_constraintTop_toBottomOf="@+id/start_time"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toLeftOf="@+id/book"/>
        <Button
            android:id="@+id/book"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Book"
            android:onClick="@{() -> itemClickListener.bookFlight(flight)}"
            style="@style/Widget.AppCompat.Button.Colored"
            app:layout_constraintBaseline_toBaselineOf="@+id/cost"
            app:layout_constraintLeft_toRightOf="@+id/cost"
            app:layout_constraintRight_toRightOf="parent" />
    </android.support.constraint.ConstraintLayout>
</layout>

RecyclerView Adapter

import android.content.Context;
import android.databinding.DataBindingUtil;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.Toast;

import java.util.List;

import zoftino.com.databinding.databinding.FlightItemLayoutBinding;

public class FlightsRecyclerViewAdapter extends
        RecyclerView.Adapter<FlightsRecyclerViewAdapter.ViewHolder>
        implements FlightsEventListener{

    private List<Flight> flightsList;
    private Context context;

    public FlightsRecyclerViewAdapter(List<Flight> flsLst, Context ctx){
        flightsList = flsLst;
        context = ctx;
    }

    @Override
    public FlightsRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                                   int viewType) {
        FlightItemLayoutBinding binding = DataBindingUtil.inflate(
                LayoutInflater.from(parent.getContext()),
                R.layout.flight_item_layout, parent, false);

        ViewHolder viewHolder = new ViewHolder(binding);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Flight flight = flightsList.get(position);
        holder.flightItemBinding.setFlight(flight);
        holder.flightItemBinding.setItemClickListener(this);
    }

    @Override
    public int getItemCount() {
        return flightsList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder{
        public FlightItemLayoutBinding flightItemBinding;

        public ViewHolder(FlightItemLayoutBinding flightItemLayoutBinding) {
            super(flightItemLayoutBinding.getRoot());
            flightItemBinding = flightItemLayoutBinding;
        }
    }
    public void bookFlight(Flight f){
        Toast.makeText(context, "You booked "+f.airLines,
                Toast.LENGTH_LONG).show();
    }
}

Event Handler

public interface FlightsEventListener {
    public void bookFlight(Flight f);
}