If you’ve been an Android developer for any length of time, you’re probably familiar with ListView. It’s a ViewGroup that displays a scrollable vertical list of views. It’s simple enough. You’ve probably also heard of RecyclerView, ListView’s newer, cooler cousin which might be good, but you probably don’t need to use it. Right?
I’ll get straight to the point: there is no real reason to continue using ListViews. This is especially true if you’re working on a new UI or app from scratch, because RecyclerViews are so much better. You could potentially save hours of time in the future by making this one choice – I know because I learned this the hard way.
But RecyclerView is too complex!
I understand why you might feel that way. RecyclerView
is certainly more powerful and more flexible than ListView
. It allows for broader functionality and actually performs better without additional boilerplate code (I’ll get to that in a bit). But it isn’t really any more complex. If you just want a vertical list, RecyclerView
can certainly give you one. Consider the following code for a ListView
adapter that displays a title and a description for each item:
public class MyListViewAdapter extends BaseAdapter {
private Context mContext;
private List<Pair<String, String>> mItems;
public MyListViewAdapter(Context context, List<Pair<String, String>> items) {
mContext = context;
mItems = items;
}
@Override
public int getCount() {
return mItems.size();
}
@Override
public Pair<String, String> getItem(int position) {
return mItems.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup container) {
MyViewHolder holder;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater)
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.item_list, container, false);
holder = new MyViewHolder();
holder.titleTextView = convertView.findViewById(R.id.text_title);
holder.descriptionTextView = convertView.findViewById(R.id.text_description);
} else {
holder = (MyViewHolder) convertView.getTag();
}
holder.titleTextView.setText(getItem(position).first);
holder.descriptionTextView.setText(getItem(position).second);
return convertView;
}
private static class MyViewHolder {
private TextView titleTextView;
private TextView descriptionTextView;
}
}
Here’s code that does the same thing using a RecyclerView
adapter:
public class MyRecyclerViewAdapter
extends RecyclerView.Adapter<MyRecyclerViewAdapter.MyViewHolder> {
private Context mContext;
private List<Pair<String, String>> mItems;
public MyRecyclerViewAdapter(Context context, List<Pair<String, String>> items) {
mContext = context;
mItems = items;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new MyViewHolder(LayoutInflater.from(mContext)
.inflate(R.layout.item_list, parent, false));
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.titleTextView.setText(getItem(position).first);
holder.descriptionTextView.setText(getItem(position).second);
}
@Override
public int getItemCount() {
return mItems.size();
}
public Pair<String, String> getItem(int position) {
return mItems.get(position);
}
static class MyViewHolder extends RecyclerView.ViewHolder {
private TextView titleTextView;
private TextView descriptionTextView;
public MyViewHolder(View itemView) {
super(itemView);
titleTextView = itemView.findViewById(R.id.text_title);
descriptionTextView = itemView.findViewById(R.id.text_description);
}
}
}
As you can see, RecyclerView
is using less code than ListView
in this example. You also probably noticed that the ListView
example above is using a common ListView
pattern called the “ViewHolder pattern”. It is basically a way of making your ListView
render views more efficiently by reusing previously rendered views using a class called the ViewHolder
. This makes sure that your views aren’t rendered from scratch every time the user scrolls to them.
Performance may not seem like a priority in this example, so using ViewHolder
could seem unnecessary, but consider what would happen if your adapter fetched some data over the internet, let’s say an image, and rendered it. Every time your user would scroll up or down a view that had already been viewed, it would fetch the data and render it again. Not only is this a terrible waste of the user’s mobile network (which is, or should be, assumed to be limited like most things in mobile devices), but it also makes for bad UX in general and goes against user expectations.
My point is, as a rule of thumb, if you’re using a ListView
, chances are you are using a ViewHolder
to recycle views and if you’re not, you probably should. Even if your adapter does not need internet access, rendering views, especially complex ones, can be an expensive task.
This is where RecyclerView
shines. If you look at the RecyclerView
example above, you can probably tell that the RecyclerView
uses the ViewHolder
pattern as well, but it does so automagically. You don’t need to check any views for null, all you need to do is create a ViewHolder
class that extends RecyclerView.ViewHolder
, declare and assign references to views in the ViewHolder
(which makes more sense than the ListView
approach), return a ViewHolder
from the onCreateViewHolder
method and modify view for each item as needed in the onBindViewHolder
method. RecyclerView
handles the recycling for you (hence the name). It’s a much cleaner, nicer approach compared with what you normally do with a ListView
.
You can use RecyclerView for other things too
RecyclerView
is more general-purpose than ListView
. This means that a RecyclerView
can do everything a ListView
can do and more, but not vice versa. For example, a ListView
can only be used for vertical lists, but RecyclerView
supports horizontal lists as well. You can even create a grid using GridLayoutManager
with RecyclerView
. And in all cases, the recycling of views is handled automatically for you.
Automatic recycling = less headache
If you’re planning on making a complex list with input fields for each view with changing data depending on user interaction, you’d be better off using RecyclerView
. With increasing code complexity, the code that would handle recycling in a ListView
also gets more complex. Having one less thing to worry about can be save you hours of time and allow you to focus on what your main task is. I know this because I’ve experienced the pain of trying to fix a problem in ListView
that just vanished when I switched over to RecyclerView
. I don’t know what exactly the problem was because I never needed to figure it out, but I know it had to do with the way I was recycling views in my ListView
manually.
So even if you’re already using ListView
and are comfortable with it, you might still want to consider switching to RecyclerView
if the code is likely to undergo any development in the future.
Conclusion
RecyclerView > ListView
RecyclerView
offers broader functionality and less boilerplate than ListView
, and it’s not more complex. In fact, the reduced boilerplate makes it arguably less complex.
I’m actually surprised ListView
still hasn’t been deprecated, but I suspect it will be eventually.