Caching made easy in android with Kotlin (Part 2)

Anurag
4 min readJan 13, 2020

--

In the last post, I talked about the basics of caching and how we can use the ColdStorage library to cache data in the android application and also persist them in shared preferences for future use. Check out the post here.

In this post, we will go a step further and cache data writing as few lines of code as possible using the power of annotations and code generation.

Let me give a brief of what we will do in as few lines as possible before jumping directly into coding.

  • We have a methods “makeRemoteCallToServiceA” and “makeRemoteCallToServiceA” that will take a few parameters and fetch data from a remote server.
  • We will put an annotation on top of this method and that will take care of caching the response from the endpoint, checking whether the data is fresh or not based on a time to live value and handle cache updation. The best part? , it will do all of these asynchronously and will not block the UI thread.

Sounds too good to be true? Not really!

Let's implement

For those who want to see the example project you can find the entire source code here.

  • Add the following in the root build.gradle file
allprojects {
repositories {
google()
jcenter()
maven { url 'https://jitpack.io' }
}
}
  • In your app build.gradle file add the the “kotlin-kapt” gradle plugin. The kotlin-kapt plugin is used for annotation processing in the project.
apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'
apply plugin: "kotlin-kapt"
  • Add the following dependencies to the application
implementation "com.github.crypticminds.ColdStorage:coldstoragecache:2.0.1"
kapt "com.github.crypticminds.ColdStorage:coldstoragecompiler:2.0.1"
implementation "com.github.crypticminds.ColdStorage:coldstorageannotation:2.0.1"
  • Now let us create a class where we will store the logic for fetching the data from an endpoint.
Request calls

Here we are making a request to the endpoint “https://httpbin.org/get” in both the methods. This endpoint simply returns the data passed to it. In the first method, the “value” parameter acts as our key while in the second “parameter1” and “parameter2” together becomes the key of our cache. If you want all the parameters to together become the key, you do not need to pass any value to the key parameter.

The annotation “@Refrigerate” can take 3 parameters. The timetoLive value will determine when a cache will be considered stale, the keys parameter where you can pass the parameters of the method that will form the key of the cache (the values of these parameters will determine the output of the method uniquely) and the mandatory operation field. Each method should have a unique operation. We will see my the operation value is needed below.

Believe it or not, your cache layer is complete. (Yes it was this simple)

Let us now go ahead and test our cache using a simple application.

MainActivity.kt

In our main activity, we initialize two text views each responsible for showing the data that we fetch from the remote calls.

Do you see the GeneratedCacheLayer in the code? You need to import the class into the activity (or wherever you need to use caching) and use this class to call the methods to fetch the data from the URLs. The method names will be the same as the ones annotated with “@Refrigerate”.This class is generated by the annotation processor to automatically create your caching layer. You will call all the methods that you annotated via this class. The package for this class will always be “com.arcane.generated”.

GeneratedCacheLayer takes the input just like your original function (in the same order) with two additional parameters. It will need the object of the class where the annotation “@Refrigerate” is used and the implementation of OnOperationsuccessfulCallback<Output> interface. The cache will send the data to the main thread using this callback.

In the above example we pass the instance of MakeRemoteCall class and the interface we implemented to the function.

In the onSuccess method, we use the operation value to determine which cached method produced the output and update our view accordingly.

The layout of the activity is shown below.

activity_main.xml

After applying the annotation you can try running your application so that the GeneratedCacheLayer file is created. Then use it just like a regular class in your project. Your IDE will be able to index it after it is generated. For the curious ones, if you check the source code in the generated file you will be able to see how a wrapper over the original methods was created to implement the caching logic.

Moment of truth

Run the application and click on the button. You will see the text views get populated with the response from the server. Keep pressing the button and take a look at the logcat section. You will see logs such as:-

2020–01–14 02:26:45.132 21851–21911/com.arcane.coldstorageexamples I/COLD_STORAGE: Cache hit
2020–01–14 02:26:46.004 21851–21911/com.arcane.coldstorageexamples I/COLD_STORAGE: Cache miss due to stale data
2020–01–14 02:26:46.283 21851–21911/com.arcane.coldstorageexamples I/COLD_STORAGE: Putting value in cache
2020–01–14 02:26:46.835 21851–21911/com.arcane.coldstorageexamples I/COLD_STORAGE: Cache hit
2020–01–14 02:26:46.835 21851–21911/com.arcane.coldstorageexamples I/COLD_STORAGE: Cache hit
2020–01–14 02:26:48.243 21851–21911/com.arcane.coldstorageexamples I/COLD_STORAGE: Putting value in cache
2020–01–14 02:26:48.993 21851–21911/com.arcane.coldstorageexamples I/COLD_STORAGE: Cache hit
2020–01–14 02:26:48.993 21851–21911/com.arcane.coldstorageexamples I/COLD_STORAGE: Cache hit
2020–01–14 02:26:50.140 21851–21911/com.arcane.coldstorageexamples I/COLD_STORAGE: Putting value in cache
2020–01–14 02:26:50.708 21851–21911/com.arcane.coldstorageexamples I/COLD_STORAGE: Cache hit
2020–01–14 02:26:50.708 21851–21911/com.arcane.coldstorageexamples I/COLD_STORAGE: Cache hit

YOUR CACHE LAYER IS FULLY FUNCTIONAL. 👏

Check out the Github repository for the ColdStorage here ▶️

--

--