In this tutorial, we’ll be discussing and implementing the RecyclerView Using Data Binding in our Android Application.

Android RecyclerView DataBinding

In order to know the basics of Android DataBinding, do visit this tutorial.

Data Binding significantly reduces the boilerplate code. Here, we’ll learn how to implement DataBinding with a RecyclerView which has the ViewHolder pattern.

Also, we’ll understand how Data Binding makes it easy to generalise the Adapter classes.

Finally, we’ll demonstrate how to directly pass the adapter object in the XML.

Getting Started

Add the following code in your app’s build.gradle:


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

Add the following dependency.


implementation 'com.android.support:design:28.0.0'

Project Structure

android-recyclerview-data-binding-project-structure

In the below application we’ll load the data in the adapter rows of the RecyclerView from the XML using the <data>. Also we’ll set the onClickListener methods in the layout rows itself.

Code

The code for the DataModel.java class is given below:


package com.journaldev.androidrecyclerviewdatabinding;
public class DataModel {
    public String androidVersion, androidName;
    public DataModel(String androidName, String androidVersion) {
        this.androidName = androidName;
        this.androidVersion = androidVersion;
    }
}

The code for the activity_main.xml layout is given below:


<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto">
    <data>
    </data>
    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </android.support.constraint.ConstraintLayout>
</layout>

MainActivity.java


package com.journaldev.androidrecyclerviewdatabinding;
import android.databinding.DataBindingUtil;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import com.journaldev.androidrecyclerviewdatabinding.databinding.ActivityMainBinding;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        populateData();
    }
    private void populateData() {
        List<DataModel> dataModelList = new ArrayList<>();
        dataModelList.add(new DataModel("Android Oreo", "8.1"));
        dataModelList.add(new DataModel("Android Pie", "9.0"));
        dataModelList.add(new DataModel("Android Nougat", "7.0"));
        dataModelList.add(new DataModel("Android Marshmallow", "6.0"));
        MyRecyclerViewAdapter myRecyclerViewAdapter = new MyRecyclerViewAdapter(dataModelList, this);
        binding.setMyAdapter(myRecyclerViewAdapter);
    }
}

The layout for each row of the RecyclerView is defined in item_row.xml.


<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="model"
            type="com.journaldev.androidrecyclerviewdatabinding.DataModel" />
        <variable
            name="itemClickListener"
            type="com.journaldev.androidrecyclerviewdatabinding.CustomClickListener" />
    </data>
    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="@{() -> itemClickListener.cardClicked(model)}"
        app:cardUseCompatPadding="true">
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_margin="8dp"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <TextView
                android:id="@+id/tvAndroidName"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{model.androidName}"
                android:textAppearance="@style/TextAppearance.AppCompat.Headline" />
            <TextView
                android:id="@+id/tvAndroidVersion"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@{model.androidVersion}"
                android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
        </LinearLayout>
    </android.support.v7.widget.CardView>
</layout>

Inside the data tag, we pass two variables – a DataModel reference and a reference of the CustomClickListener interface whose method is called in the CardView.

The code for the CustomClickListener.java is defined below:


package com.journaldev.androidrecyclerviewdatabinding;
public interface CustomClickListener {
    void cardClicked(DataModel f);
}

The code for the MyRecyclerViewAdapter.java class is given below:


package com.journaldev.androidrecyclerviewdatabinding;
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 com.journaldev.androidrecyclerviewdatabinding.databinding.ItemRowBinding;
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> implements CustomClickListener {
    private List<DataModel> dataModelList;
    private Context context;
    public MyRecyclerViewAdapter(List<DataModel> dataModelList, Context ctx) {
        this.dataModelList = dataModelList;
        context = ctx;
    }
    @Override
    public MyRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                               int viewType) {
        ItemRowBinding binding = DataBindingUtil.inflate(
                LayoutInflater.from(parent.getContext()),
                R.layout.item_row, parent, false);
        return new ViewHolder(binding);
    }
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        DataModel dataModel = dataModelList.get(position);
        holder.bind(dataModel);
        holder.itemRowBinding.setItemClickListener(this);
    }
    @Override
    public int getItemCount() {
        return dataModelList.size();
    }
    public class ViewHolder extends RecyclerView.ViewHolder {
        public ItemRowBinding itemRowBinding;
        public ViewHolder(ItemRowBinding itemRowBinding) {
            super(itemRowBinding.getRoot());
            this.itemRowBinding = itemRowBinding;
        }
        public void bind(Object obj) {
            itemRowBinding.setVariable(BR.model, obj);
            itemRowBinding.executePendingBindings();
        }
    }
    public void cardClicked(DataModel f) {
        Toast.makeText(context, "You clicked " + f.androidName,
                Toast.LENGTH_LONG).show();
    }
}

In order to pass the data to the XML counterpart we bind it using itemRowBinding.setVariable(BR.model, obj);.

executePendingBindings() is important in order to execute the data binding immediately. Otherwise it can populate incorrect view.

Difference between setVariable() and setModel()setVariable() is used in generic circumstances when the type of the data is not known.

setModel() is auto-generated. We can use the following instead of holder.bind(dataModel);.

holder.itemRowBinding.setModel(dataModel);

Passing the Adapter instance in RecyclerView XML Using Data Binding

Thanks to data binding we can further reduce the boilerplate code in our MainActivity.java by passing the adapter instance in the XML inside the android:adapter attribute as shown below:

activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="myAdapter"
            type="com.journaldev.androidrecyclerviewdatabinding.MyRecyclerViewAdapter" />
    </data>
    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adapter="@{myAdapter}"
            app:layoutManager="android.support.v7.widget.LinearLayoutManager"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </android.support.constraint.ConstraintLayout>
</layout>

In the MainActivity.java we can set the Adapter in the following way now:


MyRecyclerViewAdapter myRecyclerViewAdapter = new MyRecyclerViewAdapter(dataModelList, this);
binding.setMyAdapter(myRecyclerViewAdapter);

So there’s no need to even initialize RecyclerView in the Activity class.

The output of the above application in action is given below:

android recyclerview data binding output

That brings an end to this tutorial. You can download the project from the link below.

By admin

Leave a Reply

%d bloggers like this: