In this tutorial, we’ll be discussing and implementing the RecyclerView Using Data Binding in our Android Application.
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.
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'
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.
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);
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: That brings an end to this tutorial. You can download the project from the link below.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
I have implemented a recycler view with data binding, in this way, but from the build:Gradle:3.6.1, code is not working:- This is a log which I am getting, java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter
- Shyak Das
HI , Please share inverseBinding Adapter and Binding Adapter simple example .
- Vanshika Saini
Really nice explanation and code, the best tutorial i have found about data binding. Thanks for share!!
- Juan Antonio