Architecture Components

Android Data Binding RecyclerView

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)

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

 // lifecycle
  implementation "android.arch.lifecycle:extensions:$lifecycle_version"
  annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"

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

  // constraint layout
  implementation "com.android.support.constraint:constraint-layout:$constraint_version"

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

  // design and recyclerview
  implementation "com.android.support:recyclerview-v7:$support_version"
  implementation "com.android.support:cardview-v7:$support_version"
  implementation "com.android.support:design:$support_version"

Enable Data Binding

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

  dataBinding {
    enabled = true
  }

Designing MainActivity Layout

Open the activity_main.xml and add following code. This layout contains RecyclerView inside the ConstraintLayout. Which will be display no list item. Important things is all layout stuff inside the <layout> tag. Which mean it support 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"
    >
  <android.support.constraint.ConstraintLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:context=".MainActivity"
      tools:showIn="@layout/activity_main"
      >

    <android.support.v7.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"
        />

  </android.support.constraint.ConstraintLayout>
</layout>

Prepare Model

Let’s suppose you want display employee list using RecyclerView. The remote server API response is like 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"
    }
  ]
}
Make Employee Model

Make a model class Employee.java and put the following code inside it. I have made it Parcelable. This model class denotes name as employee name, email, id etc.

package com.example.databinding.model;

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

/**
 * Created by Morris on 05,June,2019
 */
public class Employee implements Parcelable {

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

  @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);
  }

  public final static Parcelable.Creator<Employee> CREATOR = new Creator<Employee>() {

    @SuppressWarnings({
        "unchecked"
    })
    public Employee createFromParcel(Parcel in) {
      return new Employee(in);
    }

    public Employee[] newArray(int size) {
      return (new Employee[size]);
    }
  };

  protected Employee(Parcel in) {
    this.id = ((Integer) in.readValue((Integer.class.getClassLoader())));
    this.email = ((String) in.readValue((String.class.getClassLoader())));
    this.firstName = ((String) in.readValue((String.class.getClassLoader())));
    this.lastName = ((String) in.readValue((String.class.getClassLoader())));
    this.avatar = ((String) in.readValue((String.class.getClassLoader())));
  }

  public Employee() {
  }

  public Integer getId() {
    return id;
  }

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

  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 String getLastName() {
    return lastName;
  }

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

  public String getAvatar() {
    return avatar;
  }

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

  public void writeToParcel(Parcel dest, int flags) {
    dest.writeValue(id);
    dest.writeValue(email);
    dest.writeValue(firstName);
    dest.writeValue(lastName);
    dest.writeValue(avatar);
  }

  public int describeContents() {
    return 0;
  }
}
Make EmployeeDBResponse Model

Make a 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 android.os.Parcel;
import android.os.Parcelable;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.util.List;

/**
 * Created by Morris on 05,June,2019
 */
public class EmployeeDBResponse implements Parcelable {

  @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 final static Parcelable.Creator<EmployeeDBResponse> CREATOR =
      new Creator<EmployeeDBResponse>() {

        @SuppressWarnings({
            "unchecked"
        })
        public EmployeeDBResponse createFromParcel(Parcel in) {
          return new EmployeeDBResponse(in);
        }

        public EmployeeDBResponse[] newArray(int size) {
          return (new EmployeeDBResponse[size]);
        }
      };

  protected EmployeeDBResponse(Parcel in) {
    this.page = ((Integer) in.readValue((Integer.class.getClassLoader())));
    this.perPage = ((Integer) in.readValue((Integer.class.getClassLoader())));
    this.total = ((Integer) in.readValue((Integer.class.getClassLoader())));
    this.totalPages = ((Integer) in.readValue((Integer.class.getClassLoader())));
    in.readList(this.employee, (com.example.databinding.model.Employee.class.getClassLoader()));
  }

  public EmployeeDBResponse() {
  }

  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> getEmployees() {
    return employee;
  }

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

  public void writeToParcel(Parcel dest, int flags) {
    dest.writeValue(page);
    dest.writeValue(perPage);
    dest.writeValue(total);
    dest.writeValue(totalPages);
    dest.writeList(employee);
  }

  public int describeContents() {
    return 0;
  }
}

Designing Employee List Item

Let’s create a XML layout to display employee list. This layout file contains TextViews for display name and email. One ImageView for display user profile picture. I have put all layout content inside the <layout/> .

Inside the data tag, I have declared an Employee object inside <variable/> tag. The variable name is 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)}".  

For profile picture

bind:avatar="@{employee.avatar}"
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"
      >

    <android.support.v7.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"
        >
      <android.support.constraint.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"
            />

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


      </android.support.constraint.ConstraintLayout>
    </android.support.v7.widget.CardView>

  </LinearLayout>
</layout>

Implementing Employee Data Adapter

First step is to do is create subclass of RecyclerView.Adapter. Nothings to to do special. In normal class we set data onBindViewHolder methods. In this case we already binds 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.databinding.DataBindingUtil;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
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 setEmployees(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;
    }
  }
}

Setup Retrofit Interface

Just create a interface and add the following code

package com.example.databinding.network;

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

/**
 * Created by Morris on 05,June,2019
 */
public interface EmployeeDataService {
  @GET("users/?per_page=12&amp;page=1")
  Call<EmployeeDBResponse> getEmployees();
}

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;

/**
 * Created by Morris on 05,June,2019
 */
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);
  }
}

Employee EmployeeRepository

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

package com.example.databinding.model;

import android.arch.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;

/**
 * Created by Morris on 05,June,2019
 */
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 &amp;&amp; employeeDBResponse.getEmployees() != null) {
          employees = (ArrayList<Employee>) employeeDBResponse.getEmployees();
          mutableLiveData.setValue(employees);
        }
      }

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

    return mutableLiveData;
  }
}

Create MainViewModel

Create subclass of ViewModel and add following code.

package com.example.databinding;

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

/**
 * Created by Morris on 03,June,2019
 */
public class MainActivityViewModel extends AndroidViewModel {
  private EmployeeRepository employeeRepository;

  public MainActivityViewModel(@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.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.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 MainActivityViewModel mainActivityViewModel;
  private EmployeeDataAdapter employeeDataAdapter;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ActivityMainBinding activityMainBinding =
        DataBindingUtil.setContentView(this, R.layout.activity_main);

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

    mainActivityViewModel = ViewModelProviders.of(this).get(MainActivityViewModel.class);
    employeeDataAdapter = new EmployeeDataAdapter();
    recyclerView.setAdapter(employeeDataAdapter);

    getAllEmployee();
  }

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

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

Tech Used

In this android app tutorial we have used below tech 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.

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. 

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

1
Leave a Reply

avatar
1 Comment threads
0 Thread replies
1 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
Anand Kumar Jha Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
Anand Kumar Jha
Guest
Anand Kumar Jha

Superb tutorial.