Un-jank Your Android ListView

Making a ListView scroll smoothly is a bit of a black art for Android developers, but there are a few simple rules:

  1. Use the View Holder pattern
  2. Do as little work as possible in getView()
  3. Reduce unnecessary overdraw
  4. Flatten the view hierarchy

The View Holder pattern is well known, but that second rule often gets ignored despite having the biggest impact.

Because getView() is called every time a cell is drawn, any extra work done there will slow things down. Things like formatting dates, manipulating bitmaps, querying SQLite, or loading image resources should be moved out of getView() and instead computed and cached prior to the list being populated.

Unnecessary overdraw can be caused when one view covers another one. If both views have a background, both backgrounds will be drawn even if the first is completely covered. The simplest way to find overdraw issues is to enable “Show GPU Overdraw” in the device’s developer options. If you see dark red blocks behind your ListView text after enabling that option, it’s time to work on overdraw. Simply getting rid of unnecessary background colors/drawables can make a huge difference. If you have an activity whose background is completely covered by another view, you may be able to get rid of one layer of overdraw by calling getWindow().setBackgroundDrawable(null) after setContentView() in the activity’s creation.

Flattening the view hierarchy in your layouts not only helps reduces overdraw but also means less work has to be done when the layout is inflated and drawn. When I create an XML layout, I’ll often use a ton of parent views (RelativeLayouts, LinearLayouts, etc.), to make it easier to group things and move them around. But once I’m happy with the layout, I try to remove as many of those parent views as possible.