You often encounter situations where you need to handle lists of items in mobile app development. One of the approaches you could go with is utilising ListView
and ArrayAdapter
(if your data is stored in an ArrayList
) as I explained in my previous article. This is not a bad approach but it turns out it only caters for a vertical layout.
As I was looking for a way to display my list items horizontally and scrollable, utilizing Recyclerview
appears to be one of the best approaches.
What is RecyclerView?
If you are familiar with ListView
, RecyclerView
is an improved version of it. It allows us to implement the layout more flexibly as well as to handle a larger amount of data even more efficiently. To understand RecyclerView
better, let's look at some of the features and requirements when you use RecyclerView
.
In order to utilise RecyclerView
, you need to work with RecyclerView.Adapter
, ViewHolder
and LayoutManager
. RecyclerView.Adapter
is an adapter that populates the child items of the RecyclerView
just like ArrayAdapter
. However, it requires ViewHolder
which acts as a kind of template of the child item (ViewHolder pattern). ViewHolder
is handy for the adapter as it contains the details of views within a row. Furthermore, by defining this ViewHolder pattern first, it eliminates the repetitive use of the findViewById()
method. This saves us a lot from slowing down the app performance while scrolling the items. When we utilise ArrayAdapter
, the process of recycling view was good but we still need to call the findViewById()
method multiple times to look up the elements to update the view data. Compare to this, using the ViewHolder
approach is definitely more efficient.
Now let's talk about another key player for this topic, LayoutManager
. As mentioned above, one of the benefits of using RecyclerView
is horizontal list layout and this is thanks to LayoutManager
. LayoutManager
is basically in charge of positioning child items as well as for deciding when to reuse old views. RecyclerView
offers flexible layouts and there are 3 different LayoutManager
s, which are:
-
LinearLayoutManager
: displaying items vertically or horizontally -
GridLayoutManager
: displaying items in a grid vertically or horizontally -
StaggeredGridLayoutManager
: displaying items in a staggered grid (different width/height are allowed)
By utilising these mentioned key players together, RecyclerView
can successfully create child items in an efficient way. Now let's look at a detailed example of how to use RecyclerView
.
How to use RecyclerView
In this article, we assume that we want to showcase a list of subjects in a horizontal layout. Each item includes the name of the subject, image and the number of likes. First, let's start with considering the high-level view of what we need to do:
- Define a model class called Subject to store all of your field types (subject name, image and number of likes)
- Populate your subject's data and store it in an
ArrayList
- Define the layout of each list item (2
TextView
s and 1ImageView
) - Create a custom
RecyclerView
andViewHolder
to showcase list items - Set up the custom
RecyclerView
with aLayoutManager
and adapter
Let's tackle one by one. We first need to define a class called Subject to store required fields and set up getter methods.
// Subject.java
public class Subject {
private String subject;
private int imageId;
private int numOfLikes;
// Constructor
public Subject(String subject, int imageId, int numOfLikes){
this.subject = subject;
this.imageId = imageId;
this.numOfLikes = numOfLikes;
}
//Setting up the getter methods
public String getSubject() {
return subject;
}
public int getImageId() {
return imageId;
}
public int getNumOfLikes() {
return numOfLikes;
}
}
Once we have the data model class, let's populate our ArrayList
to contain subjects details.
// MainActivity.java
ArrayList<Subject> subjectArrayList = new ArrayList<>();
subjectArrayList.add(new Subject("English", R.drawable.english, 27));
subjectArrayList.add(new Subject("Math", R.drawable.math, 13));
subjectArrayList.add(new Subject("P.E", R.drawable.pe, 45));
subjectArrayList.add(new Subject("Science", R.drawable.science, 41));
subjectArrayList.add(new Subject("Art", R.drawable.art, 36));
....etc
Next, we will quickly set up the layout of the individual item. As mentioned, we will have 2 TextViews and 1 ImageView for the example in this article. Just a side note that if you want your layout to be VERTICAL, be careful with the height of the row (root view of the list) as it needs to be wrap_content
to show your items correctly.
// list_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:orientation="vertical">
<ImageView
android:id="@+id/subject_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/subject_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<TextView
android:id="@+id/likes_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
</LinearLayout>
Now we will move on to our custom SubjectAdapter that extends the RecyclerView.Adapter
. Please note here that we need to define a custom ViewHolder to specify and give access to all of the Views. This is because we will use this custom ViewHolder
later to bind the data. It also prevents us from calling findById()
methods multiple times when the adapter assigns data to respective views.
// SubjectAdapter.java
public class SubjectAdapter extends RecyclerView.Adapter<SubjectAdapter.ViewHolder> {
// This is a template - give a direct reference to each view
public class ViewHolder extends RecyclerView.ViewHolder{
public ImageView subjectImageView;
public TextView subjectTextView;
public TextView numOfLikesTextView;
// Constructor - accepts entire row item
public ViewHolder(@NonNull View itemView) {
super(itemView);
// Find each view by id you set up in the list_item.xml
subjectImageView = itemView.findViewById(R.id.subject_image_view);
subjectTextView = itemView.findViewById(R.id.subject_text_view);
numOfLikesTextView = itemView.findViewById(R.id.likes_text_view);
}
}
}
After setting up ViewHolder, let's start working on the adapter now. There are 4 major things to do here: setting up a constructor and overriding 3 different methods, which are onCreateViewHolder()
, onBindViewHolder()
and getItemCount()
.
// SubjectAdapter.java
public class SubjectAdapter extends RecyclerView.Adapter<SubjectAdapter.ViewHolder> {
// ... ViewHolder class and its constructor as per above
ArrayList<Subject> list;
// Constructor
public SubjectAdapter(ArrayList<Subject> list){
this.list = list;
}
// Creating a viewHolder
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// Inflate the layout
View contactView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
// Return a new holder instance
ViewHolder viewHolder = new ViewHolder(contactView);
return viewHolder;
}
// Assigning respective data for the views based on the position of the current item
@Override
public void onBindViewHolder(@NonNull SubjectAdapter.ViewHolder holder, int position) {
// Get the Subject based on the current position
Subject currentItem = list.get(position);
// Setting views with the corresponding data
ImageView imageView = holder.subjectImageView;
imageView.setImageResource(currentItem.getImageId());
TextView subjectTextView = holder.subjectTextView;
subjectTextView.setText(currentItem.getSubject());
TextView likesTextView = holder.numOfLikesTextView;
likesTextView.setText(currentItem.getSubject());
}
// Indicating how long your data is
@Override
public int getItemCount() {
return list.size();
}
}
Here we start off by setting up a constructor for the adapter. Simply passing the list of data so that our adapter can utilise it to populate items. Next, let's look at the onCreateViewHolder()
method. This method is called by theLayoutManager
and it handles layout inflation when needed. Returning the ViewHolder with all of the necessary details is its role as well. Moving onto the next, the onBindViewHolder()
method plays a critical role to bind data to corresponding views. By utilising the predefined view details from the ViewHolder
, it manages to replace the content efficiently. Finally getItemCount()
method is a way to inform the adapter about the size of your data, which is the total number of items to showcase.
After going through the above process, all you need to do is to set up Recyclerview
with your custom adapter and LayoutManager
.
// MainActivity.java
// Find RecyclerView by Id (from the activity_main.xml)
RecyclerView recyclerView = findViewById(R.id.recycler_view);
// Instantiate SubjectAdapter with the data
SubjectAdapter adapter = new SubjectAdapter(subjectsList);
// Set adapter with RecyclerView
recyclerView.setAdapter(adapter);
// Set LayoutManager
recyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false));
One thing to note here is that we chose to implement LinearLayoutManage
with a horizontal layout this time. Luckily it sets to be scrollable automatically if there are many items. But if you wish to implement other styles, you could do so here by instantiating different LayoutManager
with your chosen dimension.
Summary
We have gone through how to utilise RecyclerView
with custom RecyclerView.Adapter
and LayoutManager
. This is one of the best approaches to efficiently display a list of items. I found it quite useful and it has actually more to offer such as item animation. (I will write about this when I know it better!)
Please feel free to leave a comment and your inputs are more than welcome and appreciated! Thanks for reading 😄
Top comments (0)