Wikimedia Apps/Android/Memory usage

From mediawiki.org

The following are some recommendations for improving app memory usage and performance, based on my profiling of our app.

(in rough order of priority!)

Page cache[edit]

At the moment, we cache the last 10 visited articles in memory (in the Java VM heap). This is probably a bad idea, since the size of each article is not predictable, and the VM size varies greatly across different devices and Android versions (it's as small as 24MB on older devices).

One straightforward solution to this would be to cache the pages by writing them to local storage[1]. We could probably reuse our logic for Saved Pages, and automatically "save" the page as soon as it's loaded. That way, it will be cached by default, and if the user actually wants to save the page, all we have to do is add the entry to the saved-pages sqlite table. If I'm not mistaken, this is already how it's done in the iOS app (?).

Absolutely agree with a disk cache for pages visited. Not sure what you mean with "local storage". I've been thinking of using something like JakeWharton's DiskLruCache or Android's version of it. RE:Page cache and saved pages. Once the user wants to save a page we would also have to store the images, which is encapsulated into its own AsyncTask. --Bernd

Another possible option (a very naughty one) is to use native code to allocate and store cached articles. Since these allocations would be made in the native heap instead of the Java heap, we would have access to an order of magnitude more memory. [brb need to wash hands after writing that sentence]

I'll pretend I didn't read the last paragraph about native code ;). --Bernd

Page backstack[edit]

At the moment, when the user navigates to a new article, the previous fragment is placed onto the backstack of the activity. Even though the fragment object is relatively light, if the user visits enough articles, the backstack may still eventually grow beyond the memory limit of the app, causing it to crash.

The solution to this would be... to reuse a single WebView (and thus a single fragment) for loading any number of articles[2]. I've experimented with this in the recent past, and I recall having some problems on 2.3 devices, but it may be time to revisit that patch, and iron out the issues.

Reusing the same WebView would provide additional benefits, including reduced initialization and GC cost, which will translate into better performance.

It may also be possible to do a less dramatic change, such as closing out the WebView when placing something on the back stack and reloading the page from cache when reshowing the fragment. This would still have GC churn but might be easier to implement. --brion
Yes, I think it would be good to revisit, esp. now that we don't add other fragments (history list, saved pages list, nearby) to the backstack anymore. I don't remember the issues with 2.3. Maybe we could consider using webView.loadData() and then webView.goBack() for the previous pages. Ah, I see that in the next section. --Bernd

Javascript bridge[edit]

We do some pretty heavy transactions across our "bridge" between Java and the WebView (i.e. when loading page sections). We may want to think about switching to filesystem-based section loading: after fetching a section from the network, write it to a file, and then trigger the WebView to load the section from the file[3].

Picasso cache[edit]

The Picasso library (which we use to load images from the network) automatically caches the images in local storage. This is generally a nice feature, but it seems to cache the images without any bounds. We should investigate the possibility of hooking into Picasso's caching logic, and trim the cache when it exceeds a certain limit[4].