The newer way to make Network Calls on Android

Nishant Aanjaney Jalan
CodeX
Published in
3 min readMay 9, 2022
Ktor-client for Android

We have used technologies such as Retrofit and Volley for far too long, and the industry has also adapted these very efficiently. Nonetheless, with the intense growth of Kotlin’s popularity among the Android Developers, there is a new API for making network calls in Kotlin: Ktor-client.

JetBrains is rapidly developing Kotlin every day. It is among the most loved languages in the world taking over the hearts of Android Developers. However, they did not restrict it there. We can also create a backend server with Kotlin with the API called Ktor and Ktor-client is the client version of this.

Setting up Ktor-client

As usual, we need to install the dependencies for Ktor-client. For this tutorial, we will be using the following dependencies:

def ktor_version = "1.6.8"
implementation "io.ktor:ktor-client-core:$ktor_version"
implementation "io.ktor:ktor-client-android:$ktor_version"
implementation "io.ktor:ktor-client-serialization:$ktor_version"
implementation "io.ktor:ktor-client-logging:$ktor_version"
implementation "ch.qos.logback:logback-classic:1.2.9"

Ktor-client promotes the usage of implementing modules so that we use only the modules that are required and not everything there is in Ktor.

Creating the Interface

Although with Ktor-client, it is not required to create an interface, it is a good practice to use this design pattern.

interface ApiService {
suspend fun getPost(id: String): Response<PostDto>
suspend fun createPost(post: Post): Response<PostDto>
}

and we can now implement this interface in a concrete class. This is where we will make the actual network call.

class ApiServiceImpl(
private val client: HttpClient
) : ApiService {
override suspend fun getPost(id: String): Response<PostDto> {
return try {
val response = client.get<PostDto> {
url("$BASE_URL/posts/$id/?key=value")
}
return Response.Success(response)
} catch (e: RedirectResponseException) { // 3xx
Response.Error(e.response.status.description)
} catch (e: ClientRequestException) { // 4xx
Response.Error(e.response.status.description)
} catch (e: ServerResponseException) { // 5xx
Response.Error(e.response.status.description)
}
}
[...]
}

Ktor-client is a Kotlin based Library which uses all the features that it provides. To make a GET HTTP call, we use the suspend fun get() function on the client object. The function would parse the incoming data into the generic parameter. The builder lambda function has a url() method that will take the String URL with the path parameters and the query parameters — the raw URL.

Creating the Client Object

Normally, I would encourage you to do this with Dependency Injection but for now, I’ll make a companion object inside the ApiService interface.

interface ApiService {
[...]
companion object {
val client = HttpClient(Android) {
install(Logging) {
level = LogLevel.ALL
}
install(JsonFeature) {
serializer = KotlinxSerializer()
}
}
}
}

Wrapping it up

You can now wrap everything up and start the network call. Say that you wish to get the posts whenever the user clicks on a button:

btnGetPost.setOnClickListener { _ ->
lifecycleScope.launch {
ApiService.client.use {
val service = ApiServiceImpl(it)

when (val response = service.getPost("2")) {
is Response.Success -> { /* do something */ }
is Response.Error -> toast(response.message)
}
}
}
}

Making a POST request

This is just as easy as making a get request.

override suspend fun createPost(post: Post): Response<PostDto> {
try {
val response = client.post<PostDto> {
url("$BASE_URL/posts")
contentType(ContentType.Application.Json)
setBody(post)
}
} catch ([...]) {
[ same as in the get function ]
}
}

We use the post method instead of the get. We specify the Content-Type and pass the request body.

Miscellaneous Notes

  1. Make sure that all the data classs that are used should be marked with the annotation @kotlinx.serialization.Serializable
  2. The Response class used in the above code is as follows:
sealed class Response<T> {    
data class Success<T>(val data: T) : Response<T>()
data class Error<T>(val message: String) : Response<T>()
}

3. Do not forget to add INTERNET permissions in your AndroidManifest file.

Conclusion

Ktor-client is super easy to configure and super easy to use. There are no annotations for the HTTP methods or parts of URLs. It is a plain simple network request call to make that returns the data class object that we need to work with.

--

--

Nishant Aanjaney Jalan
CodeX
Editor for

Undergraduate Student | CS and Math Teacher | Android & Full-Stack Developer | Oracle Certified Java Programmer | https://cybercoder-naj.github.io