For images downloaded from the Web, we used a server configured image resizing service so that we could request images of certain dimensions and hence download smaller images. To make sure that we maintained a high cache hit ratio on our CDN, we split the dimensions into density buckets

Resolution requested depends on screen density

For bundled images, we noticed that our placeholder images were taking a lot of memory. These are used when images are being downloaded from the web. Even though we were using one placeholder, there are multiple views rendered on the home page (20+ views depending on the logged in user) and since each view needs a placeholder, the memory consumption quickly adds up. For these, we worked with our design team to use a single color image as a placeholder for low memory devices. Android provides a isLowRamDevice() to identify if a device is a low memory device.

Return a different placeholder for low memory devices

On a low memory device, this reduced our footprint by 14%.

The next candidate on our heap dump was a surprising one; Descriptions and Titles of shows. At Viki, we pride ourselves in supporting many languages (20+ for some of the popular shows), and hence we have translations of metadata in all those languages and these are sent down to the client. Since descriptions of shows/celebrities could be very long, these strings were consuming a lot of memory. Also users rarely change their phone language, so we decided to only store the translations of the user’s current language and use English as a fallback. The fallback mechanism allowed us to cover for the scenario where a user might change their language during the usage of the app. This way, they would see descriptions in English until they restarted their app, where then we might be able to fallback to their native language, if supported.

Store descriptions in English and current language. Fetch code omitted.

The last candidate that we attacked were the view objects. Various Android talks throughout the years have tired to highlight the benefits of a flat hierarchy for performance reasons. In our scenario, we started seeing improvements on memory consumptions as well (recycler view item layouts quickly add up), since less objects were now being stored in memory. We used ConstraintLayout to flatten the view hierarchy and only modified the offending ones. It does not make sense to go on a clean driving throughout the app and might be premature.

All of these changes helped bring down our memory footprint by about 27% on low memory devices (with the extra placeholder optimisations) and by about 18% on other devices.

Reducing Data Consumption

For our data consumption, we decided to attack the low hanging fruits such as enabling WebP support (and maintaining backwards compatibility on devices that don’t support WebP). The image resizing service also allowed us to reduce the size of images that were being downloaded as we were no longer downloading the full sized image.

Furthermore, we decided to half the items per-page count for specific devices and regions (payloads add up when you have multiple language translations in them ;) ). We are also looking forward to removing those un-needed translations from payload to further reduce the data transfer.

Reducing APK Size

Proguard is one sure way to remove dead and unwanted code from your APK. Once enabled, you should instantly see its benefits reflected in your APK size. At Viki, we already had this enabled, so we decided to explore more options. We ran most of our images through TinyPNG and save big reductions in their sizes. Tiny PNG dramatically reduces each image by up to 75% (your mileage may vary). This in itself reduced our APK size by 15% without any visual difference in the graphics.

Another quick tip that I would like to highlight is the use of resConfig inside your build.gradle file. Since most libraries (especially Support library and Play Service library) include translations for many many languages, you should strip them out if you don’t support them. Resources are know to take up a lot of space and this quick tip should get that down ;)

How resConfig shaved off nearly 1Mb for us

These efforts helped us reduce our APK size by about 25%