If you've used ListView for any serious amount of time, you know the pain. View holders are optional (so everyone forgets them), layouts are limited to vertical lists, and animations feel tacked on. It's worked for years, but it never felt right.
A new widget landed in the support library recently that fixes all of this. It's called RecyclerView.
The Problem with ListView
ListView has served us well for years. But it has some fundamental limitations:
- View holders weren't enforced, leading to repeated
findViewByIdcalls - No built-in support for horizontal lists, grids, or staggered layouts
- Limited animation capabilities
- Poor decoupling between data and display
Enter RecyclerView
RecyclerView is a brand new widget that addresses all of these issues. It's part of the support library, so it works all the way back to API 7.
ViewHolder Pattern — Built In
The ViewHolder pattern is now mandatory. This means better performance out of the box:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<MyItem> items = new ArrayList<>();
public MyAdapter(List<MyItem> items) {
this.items = items;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView titleText;
TextView subtitleText;
public ViewHolder(View itemView) {
super(itemView);
titleText = (TextView) itemView.findViewById(R.id.title);
subtitleText = (TextView) itemView.findViewById(R.id.subtitle);
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_layout, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
MyItem item = items.get(position);
holder.titleText.setText(item.getTitle());
holder.subtitleText.setText(item.getSubtitle());
}
@Override
public int getItemCount() {
return items.size();
}
}
Notice how the ViewHolder caches the views. No more repetitive findViewById in getView.
LayoutManagers — One Widget, Multiple Layouts
This is the game-changer. RecyclerView delegates layout to a LayoutManager, so one widget handles everything:
// Vertical list (like ListView)
recyclerView.setLayoutManager(new LinearLayoutManager(context));
// Horizontal list
recyclerView.setLayoutManager(
new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
// Grid layout
recyclerView.setLayoutManager(new GridLayoutManager(context, 2));
// Staggered grid (Pinterest-style)
recyclerView.setLayoutManager(
new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
Same adapter, completely different layouts. That's the power of proper abstraction.
Same adapter, completely different layouts. That's the power of proper abstraction.
ItemDecoration — Clean Separation
Want dividers between items? Want custom spacing? Use ItemDecoration:
public class SpacingDecoration extends RecyclerView.ItemDecoration {
private int spacing;
public SpacingDecoration(int spacing) {
this.spacing = spacing;
}
@Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
outRect.bottom = spacing;
}
}
recyclerView.addItemDecoration(new SpacingDecoration(16));
No more messing with margins in your item layout. Clean separation of concerns.
No more messing with margins in your item layout. Clean separation of concerns.
Animations — First Class Support
RecyclerView makes animations easy:
// Default animations (add, remove, move)
recyclerView.setItemAnimator(new DefaultItemAnimator());
// Or configure specific animations
SimpleItemAnimator animator = (SimpleItemAnimator) recyclerView.getItemAnimator();
animator.setSupportsChangeAnimations(false);
animator.setAddDuration(200);
animator.setRemoveDuration(200);
You can also set initialLayoutPrefetchCount on the LayoutManager for initial load performance.
You can also animate the initial layout with layoutManager.initialLayoutPrefetchCount.
Putting It All Together
Here's a complete example:
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private MyAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
// Set up layout manager
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// Set up adapter
adapter = new MyAdapter(generateItems());
recyclerView.setAdapter(adapter);
// Add spacing
recyclerView.addItemDecoration(new SpacingDecoration(dpToPx(16)));
// Optimize performance
recyclerView.setHasFixedSize(true);
}
private List<MyItem> generateItems() {
List<MyItem> items = new ArrayList<>();
for (int i = 1; i <= 50; i++) {
items.add(new MyItem("Item " + i, "Description for item " + i));
}
return items;
}
private int dpToPx(int dp) {
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="#666666" />
</LinearLayout>
Adding the Dependency
In your build.gradle:
dependencies {
compile 'com.android.support:recyclerview-v7:23.2.0'
}
Note: The version should match your support library version.
Why This Matters
RecyclerView represents a shift in how Android thinks about lists:
- Performance — Mandatory view recycling with ViewHolder
- Flexibility — Swappable LayoutManagers for any arrangement
- Decoupling — Clean separation between data, display, and layout
- Animations — Built-in support for smooth transitions
It's not just an improved ListView — it's a fundamentally better architecture for list-based UIs.
Give it a try. Once you go RecyclerView, you won't look back.