Improve ListView Performance on Android

The performance of ListView on Android is sometimes a disaster when it comes to very complex list. Things become more frustrating when you are working with other things with Android like network images and dynamic loading.  The best example of a complex ListView is the Facebook feed in the Android app. They posted an article to show how complex but smooth ListView can be achieved at the same time.

https://code.facebook.com/posts/879498888759525/fast-rendering-news-feed-on-android/

In short, they split each post in the feed into several parts: the header, the main body and the action panel. Then each part will be able to be reused when rendering the ListView. This is a very clever alternative solution to the problematic ListView performance.

However, for my case https://github.com/cfan8/TGFC things are more complicated since the content of a post does not have a fixed style. It may be pure text, or text with some decorations, or full of images without a single line of text. Moreover, the content of the post should be interactive, i.e., when you click on a link or an image, the app should respond with different actions with that click.

In a previous open source Android app that I contributed to, we tried at least two options.

  1. Use a ListView with WebView, i.e., each item in the ListView is a WebView. In this case, it is easy to interact with other parts of the app while at the same time achieving high dynamic usability. Everything works fine when it is with Android 4.2 or before. Performance becomes a really big issue when it comes to Android 4.4, in which Google made the webkit kernel more functional but also heavier. Creating a WebView becomes a really time intensive task which we cannot afford. Thus we got several other workarounds for this problem.
    1. Keep as many WebViews as possible in the memory as cache. In the case that a user scroll down and up a WebView, the WebViews that are cached in the memory can be used directly. To keep the memory use to an acceptable level, we can use Soft Reference to cache each object.
      This workaround does not work well since when you scroll down the WebView, you are still creating new WebViews and it will only work when you scroll up and down, which is actually not very useful.
    2. Reuse each WebView. This does improved the scrolling experience since we no longer create a lot of WebViews. Instead, we alter the content of each WebView. The experience is still a little bit laggy since rendering HTML also takes a lot of time.
      This workaround worked better than the 1st one but it brings another big issue, i.e., when reusing the WebView, the height of it will not change when the length of its content changes. In other words, we will see a lot of blanks in the ListView when the length of each content of WebView varies significantly.
  2. Use a ScrollView with WebViews and render a page of posts at once. This is very brute but surprisingly work! The disadvantage of this solution is, firstly it is very memory consuming since the whole page of posts live inside the main memory. Secondly the app may froze for a second or two while rendering the page, depending on how complex the page is. However, once the page is rendered, it becomes super smooth no matter how you scroll it!

When I was figuring out the solution for the new app TGFC, I was thinking about what kind of solution I should implement. However, I realized that a WebView may not be the only option for my scenario since actually I don’t really need all the features that a heavy WebView provides. I want to have my app to be able to show some different styles of text, several images and that’s all. I don’t need stuffs like z-index or absolute positioning. In my case, TextView can work perfectly to meet my demands.

I started with a ListView of TextViews. At first, everything works fine when there is only text content in the TextView. However, things become a little bit complicated when I introduced network images into my app. Inside the ImageGetter that I was using, I first download images asynchronously to the local cache. Later on I load those images into memory and show them on the screen. I see notable lag when using ListView as the outside container when it was loading images from the local cache, so I switched to ScrollView later and rendered the whole page of posts at once.

The only thing that we need to be careful about is the usage of images. Large images can consume a lot of memory and make the ScrollView really laggy. Remember to resize those images when loading them into the memory.

Right now I still have some issues with the interaction between my TextView and the other parts of the app. I don’t have time to fix those issues and see whether they come from the HTML that Jsoup generates or the way I use TextView for the time being. But I’m pretty confident that these problems are not unsolvable and actually I have got some ideas on how to handle them. For the time being, TextView + ScrollView may be the solution for extreme complex and dynamic ListView with good user experience with better memory performance than WebView + ScrollView if you do not want to parse HTML and analyze the content to distinguish text parts and image parts.

This article is written as a complement to my Zhihu answer. In my opinion, the reason why we are having so many problems with ListView is the problematic designing of ListView that comes out from Google. Here are my suggestions on how to improve the performance of ListView from the Android designing perspective.

  1. Prepare more Views before scrolling. Currently the ListView will only prepare one more View that are invisible to the user but I believe its not enough. The number of views to be rendered should be extended.
  2. Android should introduce a kind of @PausableTask that is run on the UI thread but pausable to let the UI thread draw things to be shown on the screen. We can only show the basic outlines of the items in the initialization of a View and then gradually fill it with detailed content using the intervals of UI refresh, just like the way that Facebook used in its webpage, filling the page with place holders and filling those holders with content later on.

 

Leave a Reply

Your email address will not be published.