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
- Set ContentView using data binding
- Bind the RecyclerView
- Create an instance of the adapter and set on RecyclerView
- 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 us. It only takes about 10 seconds to register.
Get Solution Code
Still, if you have any queries please put your comment below.
17 Comments
i ca’t able to download source code from website please share github link
Dear Sir,
Kindly provide source code please
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
Where is EmployeeListItemBinding and ActivityMainBinding classes??
These are auto-generated class
excelente y actual
gracias
Greate tuto Thanks <3
how to implement with swiperefresh layout and searching ?
In this scenario, where to add an action button in recyclerview items?
Awesome
super best tutorial
Awesome Tutorial.. Good Work.. !!
nice tut
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
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
Excellent …
Superb tutorial.