Caching made easy in android with Kotlin (Part 1)

Anurag
5 min readJan 5, 2020

--

I had always underestimated the advantages that caching can bring while developing any project. However, that changed when I was shown how a good caching layer can improve a user’s experience significantly while simultaneously bringing down the expenditure of an app especially when you are relying on cloud services that will charge you for every request you make.

The strategy

Caching is simply storing data temporarily in the memory so that we can access it faster when required. It is usually used when we fetch data over the network and we would want to use it when the device is offline or we want to use the same data again within a short interval of time.

So how can we cache data in android?

  • App memory: When the app is running, we can store the data as static instances. This is the simplest form of caching but the downside to this is that the data will be lost when the application is shut down.
  • Shared preferences: A better way to cache data is by persisting them in shared preferences when we know that the data is not going to change over a while. However, shared preference is not suitable for storing complex data.
  • Database: Structured data can be cached in the device by using SQLite.
  • External storage: External storage can be used to store different kinds of data like images, videos or files.

Things to remember

  • Caching CAN NOT replace the source of truth. Caching should not be the substitute for fetching data from its source. It should be kept in mind that the cached data will get stale after some time and then the cache should be refreshed with the updated data.
  • Be careful regarding how much data you are caching. Good caching layers always delete unsued, stale data to make room for new ones.
  • Abstraction is an important factor in a good caching layer. The application logic should not have to deal with the complexities of caching. It should request the data and receive it from the cache. It is the duty of the caching layer to either make the network call to fetch the data if it is missing or stale or return it from the cache.

With all these points in mind, I created a lightweight caching library that will deal with all caching related complexities allowing the application to focus on presenting the data.

What does it do

ColdStorage will handle the following things for you while you focus solely on developing the other aspects of your application. 😃

  • Allow you to assign a fixed size to your cache so that you never hog too much memory of the device. If the data stored exceeds the specified memory, the cache will remove the oldest items to make space for new data.
  • Allow you to assign a global time to live value so that the cache is flushed when the time exceeds.
  • Allow you to assign time to live value to each item you are storing in the cache so that you can persist some data longer than others.
  • The cache handles all operations in a background thread so that your UI thread is never blocked.

How do I use it

For implementing the caching layer let us take a widely used and simple use case, displaying a downloaded image in an app.

First, let us quickly set up our android project with a blank activity. In case you are not sure how to create a new activity follow the instructions here to create your project.

Add ColdStorage to your dependencies in your build.gradle file. (Check the repo for the latest release.)

implementation 'com.github.crypticminds.ColdStorage:coldstoragecache:2.0.1'

Now the cold storage cache needs to be initialized when the application starts and the best place to do it is in the Application class. If you don’t already have one, create an Application class and extend the android.App.Application class.

Override the onCreate() function and initialize the cache by calling Cache.initialize(context = applicationContext).You can pass a global time to live value to the cache that will filter out stale data when returning anything from the cache.

Application code

Don’t forget to add the application in the manifest file by specifying the android: name attribute and add the Internet permission in the manifest as well.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="my packagename">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:name=".application.Application">

........ other details like activity
</application>

Now ColdStorage cache will be able to pull previously cached data from shared preferences and handle any stale data or size constraints.

Create a new class ImageCache extending the Cache class. You will have to implement the update method. This method is responsible for fetching the data if the data in the cache is stale or is not present.

You do not need to worry about downloading images from a separate thread in the update function as ColdStorage cache will handle all updates and downloads from background threads.

THIS IS IT. Your cache layer is ready. It is time to test your caching. 👏

Update your main activity class so that it looks like this:-

Update the view for this layer by adding a button and an ImageView where the downloaded image will be rendered:-

activity_main.xml

All the magic happens here

imageCache.get(
URLS.shuffled().take(1)[0],
this,converter)

You are requesting the cache to fetch the data for you and when the data is available, it will be available to you via the callback OnValueFetchedCallback<Any?> that the main activity has implemented.

An interesting thing to notice here is the “converter”. To understand this let’s take a look at what is happening under the hood of the cache.

The cache is created to persist the data in the SharedPreferences and since we already discussed how it is not suited for storing complex data, the cache will be storing the serialized model. Take a look at the ImageCache that we created. We convert the bitmap into a string. The converter is a class where you will specify how to convert that string back into your object and ColdStorage cache will use this to hand you back your object instead of the serialized string.

The converter is an optional parameter if you do not pass the converter the cache will return the data as a string.

The converter that transforms the string back into bitmap

Run your application and you will see the images appear on the screen. To understand when there is a cache hit or miss check the logcat section and you will see a log appear every time you press the button with the message “Cache miss” or “Cache hit”.

Congratulations, you just created your caching layer in your Kotlin app.👍

Check the part 2 of this series here.

--

--