Ever since stable Kotlin coroutines were announced at KotlinConf’18 back in October, I was very much intrigued to use them for my background tasks to give my users a streamlined experience without blocking the UI.
While working on an Android project, I came across one scenario where I was required to implement multiple asynchronous calls concurrently. Here’s how I tried to implement it using legacy Android programming and eventually implemented it using Kotlin coroutines.
The Problem
To achieve the following two tasks on the splash screen-
- Load an Interstitial Ad (which doesn’t load immediately, but takes time) and
- Make an API call to check a flag whether to show the ad or not before finishing the splash and going to the dashboard.
Failed Approaches thought of before considering the use of Kotlin coroutines:
A) Initial, step-wise (and awful) approach-
- Make an API call
2. Fetch the response & check the flag for showing an ad
3. Load the ad if the flag is true
4. Wait for the ad to load before showing the ad.
This was a lot of injustice to time, the users, the developer community, and more importantly, to Myself!
B) Second Approach-
Implement callbacks for API response (onFailure() & onSuccess()) and for Ad initialization (onAdLoaded(), and onAdClosed()) via listeners-
You know, the traditional way of returning values from asynchronous calls. Something like-
Problem with this approach. How do I combine the results from two asynchronous tasks of fetching API data and loading ads?
The solution- Kotlin coroutines
The only good approach to solve the above problem was to load ad and make an API call concurrently so that the time the user had to wait staring at the splash screen can be reduced as much as possible and suspend functions to use results from 2 async calls.
Using Kotlin coroutines’ async-await, I made the API call and loaded the ad in parallel. I then combine the results from both and show/skip ads according to the requirements mentioned above.
Code using Kotlin coroutines:
In the block- GlobalScope, I launch two coroutines in parallel using async to perform initalizeAndLoadAd() and fetchDataFromAPI(). Once I start the coroutines performing these two tasks, I call await() on each of them, and in the if condition I compare the results obtained from each of the above methods to decide the further flow of the application.
Thanks to async and await the application will wait till all the results are obtained. Once the results are obtained the criteria in the if condition above are checked to decide whether to show an ad or just navigate to the dashboard.
Problem solved? Still not.
Using suspendCoroutines
My next concern- I needed to return appropriate value from the above-mentioned callbacks such that after the asynchronous execution of calling-fetching the API and loading the ad, each of the await() should get a ‘single’ Deferred value to work with.
To achieve this, I had to make sure that the methods, fetchDataFromAPI() and initializeAndLoadAd() were suspended until either of the above callbacks associated with each returned a value.
With the use of suspendCoroutines, my code now looks something like this-
The continuation contains the completed state of the coroutine and returns a value by resuming the suspended coroutine. So, if I get a failure from the API call, my await for the API call will get null, if I get a success, my await for the API will get the response body.
Similarly, my code for loading an ad looks something like this-
If ad is loaded successfully, my await on initializeAndLoadAd() will return true else will return false.
Problem solved!
PS: This is a basic understanding I developed from multiple blogs and Stackoverflow questions. Any improvements/feedback are welcomed.