Kotlin and Retrofit 2: Tutorial with working codes

This blog, I will show you how to use Kotlin and Retrofit to read data from a server. Here, I also supply together the actual code example. Other than learning the general network call related info, hopefully you’ll get a few gist on Kotlin features that could be handy.

The Example App

The tutorial here will guide you to create an App that allow you enter a keyword, and show you how many search-count it has on wiki as the image below shows. You can get the code at the bottom of the page. The explanation of how to get there in the following sections.

The Endpoint API Server

Instead of creating our own server, let’s use an existing popular API readily available, so we could focus on just creating the Android side of code. Here we use wiki provided API that given a search-string, it will return the search-count of the hit for the provided search-string.

i.e. we’ll perform a search on https://en.wikipedia.org/w/api.php?action=query&format=json&list=search&srsearch=Trump, it will return JSON result as below, with totalhits as the count we wanted.

{
batchcomplete: "",
continue: {
sroffset: 10,
continue: "-||"
},
query: {
searchinfo: {
totalhits: 16776
},
search: [...

Also note, in the URL given, there are 4 parameters i.e. action, format, list and srsearch. For the first 3, we’ll just fix the inputs to query, json and search, while the last one is the search-string we’ll have the user provide.

The Data Model

As we have seen the JSON data up there, we are actually only interested in totalhits. Since it is contained under searchinfo and query JSON scope, to simplify the transformation of our data model, we’ll model it according to the JSON, defining it as Kotlin data class as below

object Model {
data class Result(val query: Query)
data class Query(val searchinfo: SearchInfo)
data class SearchInfo(val totalhits: Int)
}

Also do note that I wrap them in Model object, as that allows me to preserved the class easily from proguard obfuscate as described in

Add Dependent Libraries and Permission

Now, to use Retrofit, you’ll need to add the library to your gradle. Besides, you’ll also need the Rxjava library and the gson converter library, as that’s the best way to fetch data from the server known today, and automatically transform it from JSON to your data model.

Add the followings to your build.gradle

compile "com.squareup.retrofit2:retrofit:2.3.0"
compile "com.squareup.retrofit2:adapter-rxjava2:2.3.0"
compile "com.squareup.retrofit2:converter-gson:2.3.0"

compile "io.reactivex.rxjava2:rxandroid:2.0.1"

Also, don’t forget to add the needed Internet Permission in your AndroidManifest.xml

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

The Retrofit 2 Services

With the libraries included, now let’s get to the Retrofit 2 interface services definition. We define a service interface called WikiApiService. Since we only focus on one single API call, with 4 parameters of queries, I define them as below, matching the endpoint API service mentioned above.

interface WikiApiService {

@GET("api.php")
fun hitCountCheck(@Query("action") action: String,
@Query("format") format: String,
@Query("list") list: String,
@Query("srsearch") srsearch: String):
Observable<Model.Result>

}

Note: the result is return as Model.Result, and as a Observable, which is a Rxjava object that could analog as the endpoint fetcher result generator.

Once your interface is defined, you could add a static method (in your WikiApiService interface scope) that generates your retrofit service. Kotlin companion object is used to make the create function below resembler the static method of Java Factory pattern.

companion object {
fun create(): WikiApiService {

val retrofit = Retrofit.Builder()
.addCallAdapterFactory(
RxJava2CallAdapterFactory.create())
.addConverterFactory(
GsonConverterFactory.create())
.baseUrl("https://en.wikipedia.org/w/")
.build()

return retrofit.create(WikiApiService::class.java)
}
}

Here, we use the default Adaptor factory that convert between Rx Observables to Call type of retrofit, and also the default GsonConverter object.

The base Endpoint is also defined here https://en.wikipedia.org/w/.

Perform the Fetching

Once all that has been defined, it’s time for the fun bit: Fetch the data!

The Global Objects

But before that, let’s defined two global variables

val wikiApiServe by lazy {
WikiApiService.create()
}
var disposable: Disposable? = null
  1. The singleton WikiApiService object that is created lazily when the first time it is used. After that it will be reused without creation. The lazy Kotlin feature comes in really handy without the need of you writes a function explicitly to do the lazy initialization. Do note, the object is created from the WikiApiService static create function.
  2. The disposable object is basically a return object from the RxJava 2.0 that tracks the fetching activity. In the case of your Activity has been destroyed, we could dispose this object, so that your fetching event would stop, if it has not completed. This would prevent unintended crashes, in the event of your Activity has been destroyed before your fetching result return.

The Actual Fetching Code

Finally after much preparation, now you could fetch your data from wikipedia by providing the srsearch keyworld. I wrote a function below

private fun beginSearch(srsearch: String) {
disposable =
wikiApiServe.hitCountCheck("query", "json", "search", srsearch)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ result -> showResult(result.query.searchinfo.totalhits) },
{ error -> showError(error.message) }
)
}
  1. wikiApiServe is the singleton service, where hitCountCheck will return an Observable
  2. The Observable, since it’s like a endpoint fetcher result generator, we tell it to fetch the data on background by subscribeOn(Schedulers.io())
  3. However, we like the fetched data to be displayed on the MainTread (UI) so we set observeOn(AndroidSchedulers.mainThread())
  4. In term of what we do with the result, we use subscribe to define our action on the result where by the result is the fetched data result, where we could access the totalhits data accordingly. In the event of error occurs, it will return error instead to be handled.

This is so far the best model that allows a network to be done in background and post the result in mainThread.

Proper closing

Last and not least, we need to remember, since the fetching is happening on background asynchronously, there’s a possibility your activity could be terminated before the background fetch is done. So it is very important to stop the fetching mission whenever your activity is terminated.

Fortunately, using Rxjava, the disposable that we have instantiated does link to the Rx fetching handling. We could get it to terminate the process by calling dispose as below

override fun onPause() {
super.onPause()
disposable?.dispose()
}

I do it onPause, but one could handle it onDestroy or wherever make sense to your code.



I hope you appreciate this post and it’s helpful for you. Do share with others.

You could check out my other interesting topics here.

Follow me on medium, Twitter or Facebook for little tips and learning on Android, Kotlin etc related topics. ~Elye~