Tuesday, March 6, 2012

Buttery Smooth List Scrolling in Android

If I had to compare iOS to Android and only list one major benefit iOS has over Android, it would be the scrolling list performance, hands down (and I’m not the only one, or two, or three to say this...).

Seeing as scrolling lists are essential to just about every major mobile app, it affects the end user the most. Android's list view performance leads people to believe that Android is an inferior OS to iOS.

But as it turns out, with a handful of optimizations and some dedicated time, Android's scrolling performance can be just as good as iOS's performance.

You see, even though iOS does have a leg up in this department, iOS Developers still have to spent a good amount of time optimizing their scrolling lists to make them scroll smoothly. On Android, it just takes a bit more time.

When trying to improve Android's scrolling performance with a list of times, it’s important to realize the following few points:

  1. Creating objects is very expensive
  2. Calling findViewById too much can be painful
  3. Drawing on the screen should be done only when necessary

Here’s a few quick optimizations you can make to get the most performance gains for the time spent.

The first optimization is the most common one: The View Holder. It reduces the amount of objects you have to create while scrolling and dramatically cuts down  on some expensive UI calls. This optimization alone will net about 100 % increase in performance. A good example of the pattern in action can be found here.

One other less-used optimization is to only draw views when the user isn't actually scrolling the list. Here’s the idea: If your list view item consists of a few images, some text, and a checkbox, does your user really need to see all of these views generated as they are scrolling by?

When the user is scrolling by, all of the work going into calculating detailed views goes to waste, and it kills the scrolling animation.

The user also doesn’t need to have such a detailed view of scrolling data, either, only the ability to determine where the user is currently in the list. For example, in a list sorted alphabetically, you know where you are by checking the text in the list.

So instead of drawing all of these useless views while scrolling, why not only draw the text on the view? By only drawing the most important views, your list view should see a huge bump in scrolling speed, making it look much, much smoother.

For the code below to work properly, you need to add a boolean value (isScrolling) to your adapter. Any time the scrollState isn’t zero (or scrolling), you set this value to true. Once the scrolling stops, you can tell the adapter to redraw the views with the details necessary.

   1: listView.setOnScrollListener(new OnScrollListener() {
   2:  
   3: public void onScroll(AbsListView view, int firstVisibleItem,
   4: int visibleItemCount, int totalItemCoun) {
   5:     public void onScrollStateChanged(AbsListView view, int scrollState) {
   6:         if (scrollState != 0)
   7:             listView.getAdapter()).isScrolling = true;
   8:         else {
   9:             listView.getAdapter()).isScrolling = false;
  10:             listView.getAdapter()).notifyDataSetChanged();
  11:         }
  12:     }
  13: });
  14:  


After you add the above code in your listView.getView() method, you can use the newly added boolean value to determine if any performance-intensive views need to be drawn or not, like images or complex buttons.

The above two optimizations will give you a good jump in performance for a minimal amount of invested time.

Do you know of some other hidden optimization gems for Android’s List View performance?

7 comments:

  1. I'm running sense 3.5, could you explain this deeper? I understand adding this code, but I quietly don't understand boolean

    ReplyDelete
  2. This is awesome! I was looking for exactly this code so I could disable image rendering in the listview and enable images when scrolling stopped. If I could determine the velocity of the scrolling that would be a nice addition. So the the images could be rendered during slow scrolling but not when the scrolling was fast.

    ReplyDelete
    Replies
    1. can i have its implementation in live project becoz i m not able to use this code.

      Delete
  3. boolean = true or false

    ReplyDelete
  4. Strange thing happens on one of my test phones: when scroll reaches the bottom of the list onScrollStateChanged is not called. That phone has android 2.2. It works perfectly fine on the phone with android 2.3...

    ReplyDelete
    Replies
    1. Im using 2.3.3 and the if/else statement gives me errors...

      Delete
  5. i m getting redline under isScrolling .. :( :(
    pls help me

    ReplyDelete