Android Jetpack

Android Data Binding RecyclerView

Pinterest LinkedIn Tumblr

Introduction

In this android data binding RecyclerView tutorial, I’m going to show how to implement data binding in RecyclerView Android. Data binding binds the UI with data sources and reduced line of code. In this android data binding RecyclerView tutorial, we take an entity is an employee. That means is we fetch the employee data from remote and display on RecyclerView.

What is RecyclerView

RecyclerView is self-explanatory, It widget is a more advanced and flexible version of ListView. For more detail read out this blog post: RecyclerView in Android

What is Data binding

Data Binding is part of android architecture components. It allows us to bind the UI components to data sources in a declaration format.

For more information on DataBinding, check out this blog post: Data Binding in Android Tutorial

Android Data Binding RecyclerView Example (Sample App)

Example App

All theoretical part is done. Now come to real implementation. I’m going to example app that contains Retrofit, LiveData, and DataBinding with RecyclerView. After following all steps the final outcome is the same as video. How to do that let’s get started

1. Add dependencies

Let move to android studio and open module app build.gradle and add below dependencies. Make sure you have added latest version of dependencies

  implementation 'androidx.appcompat:appcompat:1.0.2'
  // constraint layout
  implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

  // lifecycle
  implementation "android.arch.lifecycle:extensions:1.1.1"
  annotationProcessor "android.arch.lifecycle:compiler:1.1.1"

  // glide for image
  implementation "com.github.bumptech.glide:glide:4.9.0"
  annotationProcessor "com.github.bumptech.glide:compiler:4.9.0"

  // retrofit
  implementation "com.squareup.retrofit2:retrofit:2.6.0"
  implementation 'com.squareup.retrofit2:converter-gson:2.4.0'

  implementation 'androidx.recyclerview:recyclerview:1.0.0'
  implementation 'androidx.cardview:cardview:1.0.0

2. Enable Data Binding

You know we are going to data binding in app tutorials. Just add below line inside android tag

  dataBinding {
    enabled = true
  }

3. Designing MainActivity Layout

Open the activity_main.xml and add following code. This layout contains RecyclerView inside the ConstraintLayout. Which will be displayed no list item. Important things are all layout stuff inside the <layout> tag. Which mean it supports data binding

<?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"
    >
  <androidx.constraintlayout.widget.ConstraintLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:context=".MainActivity"
      tools:showIn="@layout/activity_main">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/viewEmployees"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        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>

4. Prepare Model

Let’s suppose you want to display the employee’s list using RecyclerView. The JSON contract is below

{
  "page": 1,
  "per_page": 3,
  "total": 12,
  "total_pages": 4,
  "data": [
    {
      "id": 1,
      "email": "george.bluth@reqres.in",
      "first_name": "George",
      "last_name": "Bluth",
      "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg"
    },
    {
      "id": 2,
      "email": "janet.weaver@reqres.in",
      "first_name": "Janet",
      "last_name": "Weaver",
      "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg"
    },
    {
      "id": 3,
      "email": "emma.wong@reqres.in",
      "first_name": "Emma",
      "last_name": "Wong",
      "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/olegpogodaev/128.jpg"
    }
  ]
}
5. Make Employee Model

Create a model class named is Employee.java and paste the below code inside this file. This is a model class that contains a name, email, id, etc.

package com.example.databinding.model;

import android.widget.ImageView;
import androidx.databinding.BindingAdapter;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.example.databinding.R;
import com.google.gson.annotations.SerializedName;

public class Employee {

  @SerializedName("avatar")
  private String avatar;
  @SerializedName("email")
  private String email;
  @SerializedName("first_name")
  private String firstName;
  @SerializedName("id")
  private Long id;
  @SerializedName("last_name")
  private String lastName;

  public String getAvatar() {
    return avatar;
  }

  public void setAvatar(String avatar) {
    this.avatar = avatar;
  }

  public String getEmail() {
    return email;
  }

  public void setEmail(String email) {
    this.email = email;
  }

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  // important code for loading image here
  @BindingAdapter({ "avatar" })
  public static void loadImage(ImageView imageView, String imageURL) {
    Glide.with(imageView.getContext())
        .setDefaultRequestOptions(new RequestOptions()
            .circleCrop())
        .load(imageURL)
        .placeholder(R.drawable.loading)
        .into(imageView);
  }
}

Let’s see the above class. In this class, we are adding one method name loadImage() which annotated with @BindingAdapter({ “avatar” }) . Actually, here I’m binding avatar image with ImageView. It is using glide for loading images.

6. Make EmployeeDBResponse Model

Create an EmployeeDBResponse.java model class. I take name EmployeeDBResponse that mean this is server database response. This model class contains employee list and no of page etc.

package com.example.databinding.model;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.util.List;

public class EmployeeDBResponse {
  @SerializedName("page")
  @Expose
  private Integer page;
  @SerializedName("per_page")
  @Expose
  private Integer perPage;
  @SerializedName("total")
  @Expose
  private Integer total;
  @SerializedName("total_pages")
  @Expose
  private Integer totalPages;
  @SerializedName("data")
  @Expose
  private List<Employee> employee = null;

  public Integer getPage() {
    return page;
  }

  public void setPage(Integer page) {
    this.page = page;
  }

  public Integer getPerPage() {
    return perPage;
  }

  public void setPerPage(Integer perPage) {
    this.perPage = perPage;
  }

  public Integer getTotal() {
    return total;
  }

  public void setTotal(Integer total) {
    this.total = total;
  }

  public Integer getTotalPages() {
    return totalPages;
  }

  public void setTotalPages(Integer totalPages) {
    this.totalPages = totalPages;
  }

  public List<Employee> getEmployee() {
    return employee;
  }

  public void setEmployee(List<Employee> employee) {
    this.employee = employee;
  }
}

7. Designing Employee List Item

Let’s create a layout to display list item. This layout file contains TextViews for the display employee details. I have put all layout content inside the <layout/> tag. Basically, data binding layout we have to put inside <layout/> tag.

Inside the <layout/> tag, I have declared an Employee object inside <variable/> tag. The variable name is an employee. Using this variable I have set the value of each widget, Such as I have set user name like

android:text="@{employee.firstName.concat(@string/space).concat(employee.lastName)}"
bind:avatar="@{employee.avatar}"

For profile picture

8. Full XML file looks like this
<?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:tools="http://schemas.android.com/tools">
  <data>
    <variable
        name="employee"
        type="com.example.databinding.model.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">
        <ImageView
            android:id="@+id/ivPic"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_marginBottom="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:background="?attr/selectableItemBackgroundBorderless"
            android:scaleType="fitXY"
            bind:avatar="@{employee.avatar}"
            bind:layout_constraintBottom_toBottomOf="parent"
            bind:layout_constraintStart_toStartOf="parent"
            bind:layout_constraintTop_toTopOf="parent"
            android:layout_marginLeft="8dp"/>

        <TextView
            android:id="@+id/tvFullName"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_below="@+id/ivPic"
            android:layout_marginEnd="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:padding="4dp"
            android:text="@{employee.firstName.concat(@string/space).concat(employee.lastName)}"
            android:textColor="@color/colorPrimary"
            android:textSize="18sp"
            bind:layout_constraintEnd_toEndOf="parent"
            bind:layout_constraintStart_toEndOf="@+id/ivPic"
            bind:layout_constraintTop_toTopOf="parent"
            tools:text="Morris"/>

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

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

9. Implementing Employee Data Adapter

Let’s create a RecyclerView Adapter class for holding employee list items. In a normal class, we need to bind the view with corresponding data object inside onBindViewHolder() methods. In this case, we already bind employee model data inside the layout file.

Now we have to attached item layout using data binding onCreateViewHolder() and set the item data over the employee object.

package com.example.databinding.adapter;

import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
import com.example.databinding.R;
import com.example.databinding.databinding.EmployeeListItemBinding;
import com.example.databinding.model.Employee;
import java.util.ArrayList;

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

  private ArrayList<Employee> employees;

  @NonNull
  @Override
  public EmployeeViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
    EmployeeListItemBinding employeeListItemBinding =
        DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()),
            R.layout.employee_list_item, viewGroup, false);
    return new EmployeeViewHolder(employeeListItemBinding);
  }

  @Override
  public void onBindViewHolder(@NonNull EmployeeViewHolder employeeViewHolder, int i) {
    Employee currentStudent = employees.get(i);
    employeeViewHolder.employeeListItemBinding.setEmployee(currentStudent);
  }

  @Override
  public int getItemCount() {
    if (employees != null) {
      return employees.size();
    } else {
      return 0;
    }
  }

  public void setEmployeeList(ArrayList<Employee> employees) {
    this.employees = employees;
    notifyDataSetChanged();
  }

  class EmployeeViewHolder extends RecyclerView.ViewHolder {

    private EmployeeListItemBinding employeeListItemBinding;

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

      this.employeeListItemBinding = employeetListItemBinding;
    }
  }
}

11. Setup Retrofit Interface

Let’s set up Retrofit for APIs calling

1. Interface
package com.example.databinding.network;

import com.example.databinding.model.EmployeeDBResponse;
import retrofit2.Call;
import retrofit2.http.GET;

public interface EmployeeDataService {
  @GET("users/?per_page=12&page=1")
  Call<EmployeeDBResponse> getEmployees();
}
2. Create Retrofit Client

Make a retrofit service builder class that return the object EmployeeDataService

package com.example.databinding.network;

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitClient {
  private static Retrofit retrofit;
  private static final String BASE_URL = "https://reqres.in/api/";

  public static EmployeeDataService getService() {
    if (retrofit == null) {
      retrofit = new Retrofit
          .Builder()
          .baseUrl(BASE_URL)
          .addConverterFactory(GsonConverterFactory.create())
          .build();
    }

    return retrofit.create(EmployeeDataService.class);
  }
}

12. Create EmployeeRepository

Let’s create an employee data Repository, that deal with the network and provide MutableLiveData instance.

package com.example.databinding.model;

import androidx.lifecycle.MutableLiveData;
import com.example.databinding.network.EmployeeDataService;
import com.example.databinding.network.RetrofitClient;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class EmployeeRepository {
  private static final String TAG = "EmployeeRepository";
  private ArrayList<Employee> employees = new ArrayList<>();
  private MutableLiveData<List<Employee>> mutableLiveData = new MutableLiveData<>();

  public EmployeeRepository() {
  }

  public MutableLiveData<List<Employee>> getMutableLiveData() {

    final EmployeeDataService userDataService = RetrofitClient.getService();

    Call<EmployeeDBResponse> call = userDataService.getEmployees();
    call.enqueue(new Callback<EmployeeDBResponse>() {
      @Override
      public void onResponse(Call<EmployeeDBResponse> call, Response<EmployeeDBResponse> response) {
        EmployeeDBResponse employeeDBResponse = response.body();
        if (employeeDBResponse != null && employeeDBResponse.getEmployee() != null) {
          employees = (ArrayList<Employee>) employeeDBResponse.getEmployee();
          mutableLiveData.setValue(employees);
        }
      }

      @Override
      public void onFailure(Call<EmployeeDBResponse> call, Throwable t) {
      }
    });

    return mutableLiveData;
  }
}

13. Create MainViewModel

Create subclass of AndroidViewModel and add following code.

package com.example.databinding;

import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import com.example.databinding.model.Employee;
import com.example.databinding.model.EmployeeRepository;
import java.util.List;

public class MainViewModel extends AndroidViewModel {
  private EmployeeRepository employeeRepository;

  public MainViewModel(@NonNull Application application) {
    super(application);
    employeeRepository = new EmployeeRepository();
  }

  public LiveData<List<Employee>> getAllEmployee() {
    return employeeRepository.getMutableLiveData();
  }
}

Update MainActivity

Now, declare all these objects inside MainActivity. Basically, four things we have do inside MainActivity

  1. Set ContentView using data binding
  2. Bind the RecyclerView
  3. Create an instance of the adapter and set on RecyclerView
  4. Get data from server using from EmployeeRepository and notify the adapter
Doing all above step the final code is
package com.example.databinding;

import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.databinding.adapter.EmployeeDataAdapter;
import com.example.databinding.databinding.ActivityMainBinding;
import com.example.databinding.model.Employee;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
  private MainViewModel mainViewModel;
  private EmployeeDataAdapter employeeDataAdapter;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityMainBinding activityMainBinding =
        DataBindingUtil.setContentView(this, R.layout.activity_main);

    // bind RecyclerView
    RecyclerView recyclerView = activityMainBinding.viewEmployees;
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setHasFixedSize(true);

    mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
    employeeDataAdapter = new EmployeeDataAdapter();
    recyclerView.setAdapter(employeeDataAdapter);
    getAllEmployee();
  }

  private void getAllEmployee() {
    mainViewModel.getAllEmployee().observe(this, new Observer<List<Employee>>() {
      @Override
      public void onChanged(@Nullable List<Employee> employees) {
        employeeDataAdapter.setEmployeeList((ArrayList<Employee>) employees);
      }
    });
  }
}

That all about android data binding in RecyclerView. That’s All! Happy Coding 🙂

Technology Used

In this android app tutorial, we have used below Technology stack

  • LiveData
  • Data Binding
  • Retrofit
  • Glide

Conclusion

With the help of this android app tutorial, We have learned how to implement Android Data Binding RecyclerView. I hope it’s helpful for you, Help me by sharing this post with all your friends who learning android app development. Read this article for deep drive of livedata with coroutines.

Keep in touch

If you want to keep in touch and get an email when I write new blog posts, follow me on facebook or subscribe usIt only takes about 10 seconds to register. 

Get Solution Code

Still, if you have any queries please put your comment below.

17 Comments

  1. Amit Tiwari Reply

    i ca’t able to download source code from website please share github link

  2. Fonkou Christian Reply

    Hello Guys this is very cool i have implement it without any problem now i want to know how to do live data and add search bar on it.

    Thank

  3. Where is EmployeeListItemBinding and ActivityMainBinding classes??

  4. Feroz Khan Reply

    In this scenario, where to add an action button in recyclerview items?

  5. Very helpful tutorial! Although, this 3 informations are missing:

    1. You need kotlin kapt plugin and databinding compiler
    https://stackoverflow.com/questions/53160991/cannot-find-setter-for-attribute-appvisiblegone

    2. You need this html in your strings file \u0020 for the concat work for employee name
    https://stackoverflow.com/questions/40039942/i-want-to-concat-two-strings-for-a-textview-in-android-data-binding-api

    3. It is necessary to add @JvmStatic to the bindingAdapter loadImage function
    https://stackoverflow.com/questions/51875634/can-not-use-bindingadapter-in-kotlin

  6. Manoochehr Totonchi Reply

    Hi
    if you can put the source for this guide in here is will be very great

    now i have the error:
    error: cannot find symbol class OffersListItemBindingImpl

Write A Comment