Android Data Binding In RecyclerView

In the previous article, we have learned about the Basics of dataBinding.Now In this android data binding RecyclerView tutorial, I’m going to show how to implement data binding in Android RecyclerView. Data binding binds the UI with data sources and reduces lines of code.

Using DataBinding in an adapter class keeps the code to very minimal as lot of things will be taken care in the layout itself.

Get GITHUB code from here.

Creating New Project

1. Create a new project in Android Studio from File New Project and fill the project details.

2. Enable DataBinding in app/build.gradle. Also add the RecyclerView, CardView and CircleImageView dependencies and Sync the project.

android {

    dataBinding { 
     enabled = true
     }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'

    //recyclerView
    implementation 'androidx.recyclerview:recyclerview:1.0.0'

    //cardView
    implementation 'androidx.cardview:cardview:1.0.0'

    //circleImageView
    implementation 'de.hdodenhof:circleimageview:3.1.0'

    androidTestImplementation 'androidx.test:runner:1.2.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

3. Add the below string-array for name and email in your strings.xml.

strings.xml

<string-array name="names">
    <item>Arun Chandravanshi</item>
    <item>Pravesh Kumar</item>
    <item>Ranu Deshmuk</item>
    <item>Neelam Roy</item>
    <item>Nikita Desai</item>
    <item>Mohan Bhatiya</item>
    <item>Anikesh Danial</item>
    <item>Chris Danial </item>
    <item>Koshiki Chandravanshi</item>
    <item>Neha pandey</item>


</string-array>

<string-array name="emails">

    <item>arun11@gmail.com</item>
    <item>pravesh12@gmail.com</item>
    <item>ranu13@gmail.com</item>
    <item>neelam14@gmail.com</item>
    <item>nikita15@gmail.com</item>
    <item>mohan16@gmail.com</item>
    <item>anikesh17@gmail.com</item>
    <item>chris18@gmail.com</item>
    <item>koshiki19@gmail.com</item>
    <item>neha20@gmail.com</item>


</string-array>

4. Open the layout file of main activity i.e activity_main.xml. Enable data-binding by adding <layout> tag and inside root view, add RecyclerView.

activity_main.xml

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

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scrollbars="vertical"
            android:layout_marginBottom="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginRight="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:padding="4dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

5. Create a model class named Employee.java. This class provides data to RecyclerView.

Employee.java

package com.example.databindingdemo;

import android.view.View;

import androidx.core.content.ContextCompat;
import androidx.databinding.BindingAdapter;
import de.hdodenhof.circleimageview.CircleImageView;

public class Employee {

    public String name, email;
    public int imageId;

    public Employee(String name, String email, int imageId) {
        this.name = name;
        this.email = email;
        this.imageId = imageId;
    }

    //code for loading image
    @BindingAdapter("android:imageUrl")
    public static void loadImage(View view, int imageId) {

        CircleImageView imageView = (CircleImageView) view;

        imageView.setImageDrawable(ContextCompat.getDrawable(imageView.getContext(), imageId));
    }
}

In the above class, we are adding one method name loadImage() which annotated with @BindingAdapter(“android:imageUrl”).

Using BindingAdapters you can create custom attributes for your views.

<de.hdodenhof.circleimageview.CircleImageView
    android:id="@+id/emp_image"
    android:layout_width="80dp"
    android:layout_height="80dp"
    app:civ_border_width="2dp"
    android:imageUrl="@{employee.imageId}"
    android:scaleType="centerCrop"
    app:civ_border_color="#FF000000"/>

Now the above custom attribute imageUrl defined in CircleImageView gets linked with the loadImage(). That means whenever this attribute will read for any employee object then loadImage() will be called and it will set the drawable Image to ImageView.

DataBinding In RecyclerView

Binding a RecyclerView layout is similar to normal binding except few changes in onCreateViewHolder and onBindViewHolder methods.

6. Create layout named employee_list_item.xml. This layout contains one ImageView and two TextViews (for name and email ) to render employee data in RecyclerView.

  • In this layout, data binding is enabled by keeping the root element as <layout>. The Employee model is bound to this layout using <variable> tag.

employee_list_item.xml

<?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:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="employee"
            type="com.example.databindingdemo.Employee" />

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true">

        <androidx.cardview.widget.CardView
            android:id="@+id/cvEmployee"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:layout_margin="5dp"
            android:elevation="3dp"
            card_view:cardCornerRadius="1dp">

            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <de.hdodenhof.circleimageview.CircleImageView
                    android:id="@+id/emp_image"
                    android:layout_width="80dp"
                    android:layout_height="80dp"
                    app:civ_border_width="2dp"
                    android:layout_marginStart="8dp"
                    android:layout_marginLeft="8dp"
                    android:layout_marginTop="8dp"
                    android:layout_marginBottom="8dp"
                    android:background="?attr/selectableItemBackgroundBorderless"
                    android:imageUrl="@{employee.imageId}"
                    android:scaleType="centerCrop"
                    bind:layout_constraintBottom_toBottomOf="parent"
                    bind:layout_constraintStart_toStartOf="parent"
                    bind:layout_constraintTop_toTopOf="parent"
                    app:civ_border_color="#FF000000"/>


                <TextView
                    android:id="@+id/tvFullName"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/emp_image"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:layout_marginEnd="8dp"
                    android:padding="4dp"
                    android:text="@{employee.name}"
                    android:textColor="@color/colorPrimary"
                    android:textSize="18sp"
                    bind:layout_constraintEnd_toEndOf="parent"
                    bind:layout_constraintStart_toEndOf="@+id/emp_image"
                    bind:layout_constraintTop_toTopOf="parent" />

                <TextView
                    android:id="@+id/tvEmail"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/tvFullName"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="4dp"
                    android:layout_marginEnd="8dp"
                    android:padding="4dp"
                    android:text="@{employee.email}"
                    android:textColor="@color/colorAccent"
                    android:textSize="16sp"
                    bind:layout_constraintEnd_toEndOf="parent"
                    bind:layout_constraintStart_toEndOf="@+id/emp_image"
                    bind:layout_constraintTop_toBottomOf="@+id/tvFullName" />

            </androidx.constraintlayout.widget.ConstraintLayout>
        </androidx.cardview.widget.CardView>
    </LinearLayout>


</layout>

7. Create a class named EmployeeDataAdapter.java under the root folder.

  • As the layout name is employee_list_item.xml, the generated binding class will be EmployeeListItemBinding.
  • In onCreateViewHolder() method, employee_list_item layout is inflated with the help of EmployeeListItemBinding class.
  • holder.binding.setEmployee() binds the Employee model to each row.

EmployeeDataAdapter.java

package com.example.databindingdemo;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;

import com.example.databindingdemo.databinding.EmployeeListItemBinding;

import java.util.List;

import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;

public class EmployeeDataAdapter extends RecyclerView.Adapter<EmployeeDataAdapter.EmployeeViewHolder> {

    Context context;
    List<Employee> employeeList;

    public EmployeeDataAdapter(Context context, List<Employee> employeeList) {
        this.context = context;
        this.employeeList = employeeList;
    }

    @NonNull
    @Override
    public EmployeeViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        EmployeeListItemBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.employee_list_item, parent, false);

        return new EmployeeViewHolder(binding);

    }

    @Override
    public void onBindViewHolder(@NonNull EmployeeViewHolder holder, int position) {

        Employee employee = employeeList.get(position);

        holder.binding.setEmployee(employee);
    }

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

    class EmployeeViewHolder extends RecyclerView.ViewHolder {

        private EmployeeListItemBinding binding;

        public EmployeeViewHolder(@NonNull EmployeeListItemBinding binding) {
            super(binding.getRoot());

            this.binding = binding;
        }
    }
}

8. Finally open MainActivity.java and do the below modifications.

  • As the main activity layout name is activity_main, the generated binding class will be ActivityMainBinding.
  • prepareData() will prepare list of employees which we will pass to EmployeeDataAdapter.

MainActivity.java

package com.example.databindingdemo;

import android.os.Bundle;

import com.example.databindingdemo.databinding.ActivityMainBinding;

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

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.LinearLayoutManager;

public class MainActivity extends AppCompatActivity {

    ActivityMainBinding binding;


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


        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));


        binding.recyclerView.setAdapter(new EmployeeDataAdapter(this, prepareData()));
    }


    public List<Employee> prepareData() {

        List<String> names = Arrays.asList(getResources().getStringArray(R.array.names));
        List<String> emails = Arrays.asList(getResources().getStringArray(R.array.emails));

        int[] imageIds = {R.drawable.boy_img2, R.drawable.boy_img1, R.drawable.girl_img1, R.drawable.girl_img2, R.drawable.girl_img3, R.drawable.boy_img3, R.drawable.boy_img5, R.drawable.boy_img4, R.drawable.girl_img5, R.drawable.girl_img4};

        List<Employee> employeeList = new ArrayList<>();

        int count = 0;

        for (String name : names) {
            employeeList.add(new Employee(name, emails.get(count), imageIds[count]));
            count++;
        }

        return employeeList;
    }
}

When you run your application it will look like this:

Screenshot_1582208918

In the next article, we will talk about how to work with Observable data objects using dataBinding.

Leave a Reply