Kotlin Ktor Android Client – Simplifying Android Networking

Hello everyone! Today, we’re exploring a new way to handle network calls in Android using the “Kotlin KTor Android Client”. While Retrofit is a good choice, we’ll also look into situations where using KTor could …

Kotlin Ktor Android Client

Hello everyone! Today, we’re exploring a new way to handle network calls in Android using the “Kotlin KTor Android Client”. While Retrofit is a good choice, we’ll also look into situations where using KTor could be helpful. If you’re using Retrofit now, no worries – both options work well, and we’ll talk about when choosing the Kotlin KTor Android Client might be a good idea.

This tutorial is a segment of my free course titled “Architecting Excellence: A Deep Dive into Multi-Module Android Apps.” You can find the complete course on YouTube, where I delve into essential topics in modern Android app development. Below, you’ll find the video corresponding to this post, offering a visual walkthrough. Feel free to check it out if you prefer a more interactive learning experience.

If you’ve landed here solely for the source code of this project, you can find it below.

Kotlin Ktor Android Client

Kotlin has a handy tool called Ktor. It helps you build servers and clients that can handle tasks asynchronously. So, if you want to make RESTful APIs for your app using Kotlin, you’re in luck. I’ve got a detailed guide on how to do just that with the Ktor Framework. But what’s even cooler about Ktor is its Android client. This means you can use it to easily manage network tasks in your Android apps. Pretty neat, huh?

In this post, we’ll learn about using the Kotlin Ktor Android Client in our Android project. But before we get into that, let’s talk about why you might choose Ktor when you already have Retrofit.

While Retrofit remains a reliable option, there’s no compelling reason to suggest migrating to Ktor Android Client unless you’re working with Kotlin Multiplatform. Retrofit doesn’t support Kotlin Multiplatform, and nowadays, many developers are opting for a consistent data layer across Android and iOS apps using Kotlin Multiplatform. If your project doesn’t involve Kotlin Multiplatform, sticking with Retrofit is perfectly fine. I’ll highlight some advantages of Ktor below, but none of them is a dealbreaker for Retrofit. So, if you’re comfortable with Retrofit in your project, that’s absolutely fine.

Advantages of Ktor Android Client

  1. Coroutines Ease: Ktor makes writing asynchronous code a breeze by fully embracing Kotlin Coroutines.
  2. Feature-Rich: Unlike Retrofit, which is mainly for API calls, Ktor goes beyond that. It’s a feature-rich framework that allows you to build entire backends and supports various protocols, not just HTTP.
  3. Concise Code: Kotlin is known for being concise, and Ktor inherits this trait. This means your code can be more straightforward to understand.
  4. Kotlin Consistency: Ktor is a pure Kotlin framework, that provides consistency throughout your project. If your team uses Kotlin everywhere, Ktor seamlessly fits in, making it handy for Kotlin-centric developers.
  5. Built-in Goodies: Ktor comes with built-in features for many tasks like Content-Negotiation, Authentication, OAuth, and more. This can save you time and effort in handling common functionalities.

Alright, no more talking – let’s dive into some hands-on implementation. We’ll see how to use the Ktor Android Client to handle networking in your Android app.

Setting Up Dependencies

Whether you’re starting a new project in Android Studio or working with an existing one, the first thing to do is set up the Ktor Android client dependencies.

In your project’s app-level build.gradle file, just make sure to add these dependencies in the dependencies block. This simple step ensures that your project is ready to use Ktor’s Android client features smoothly.

As we are going to use kotlinx serialization, we also need to add kotlinx serialization plugin.

Once you’ve added the mentioned dependencies, your project is all set to make use of Ktor. Now, you can easily integrate and use Ktor features in your Android project.

Creating an HttpClientBuilder

Let’s architect a class that acts as an HttpClient provider, seamlessly facilitating the execution of network requests. By leveraging the builder pattern for enhanced ease of use and comprehension, this class guarantees a direct and user-friendly approach to obtaining the HttpClient object.

Understanding our HttpClientBuilder

The given code defines a Kotlin class named MyHttpClientBuilder. This class is responsible for creating and configuring instances of the HttpClient, a component used for making network requests. Now, let’s go through the key components and functionalities step by step.

  1. Class Structure:
    • The class has private properties, namely protocol and host, used to store the URL protocol and host details.
    • It provides three functions: protocol, host, and build.
  2. Protocol and Host Configuration:
    • The protocol function allows the user to set the URL protocol (defaulting to HTTP) and returns the modified builder instance.
    • The host function enables the user to set the host for the network request and returns the modified builder instance.
  3. Building the HttpClient:
    • The build function creates and configures an instance of HttpClient using the CIO (Coroutine I/O) engine.
    • It sets various configurations for the engine, such as keep-alive time, connect timeout, and attempts for connection retries.
  4. Default Request Configuration:
    • The default request configuration includes setting the URL protocol and host based on the values provided.
    • Additionally, it sets the request header to indicate that the content type is JSON.
  5. Content Negotiation:
    • Content negotiation is installed to handle JSON serialization and deserialization.
    • It uses the kotlinx.serialization library with specific settings like pretty printing and leniency.
  6. Authentication:
    • Authentication is installed with a bearer token approach.
    • The code includes a mechanism for handling access and refresh tokens, which are crucial for authentication. It’s important to note that at this point, no tokens are provided explicitly. If required, you can supply the tokens, or alternatively, retrieve them from your session handler instance. I’ve extensively covered session handling in my course titled “Architecting Excellence: A Deep Dive into Multi-Module Android Apps.”
  7. Logging:
    • Logging is configured to print log messages to the console with a specified logger implementation.
    • The log level is set to capture all log messages.
  8. Returning the Configured HttpClient:
    • The final configured HttpClient instance is returned from the build function.

In summary, the MyHttpClientBuilder class simplifies the creation of HttpClient instances by providing a fluent interface for configuring various aspects like protocol, host, engine settings, default request headers, content negotiation, authentication, and logging. The builder pattern makes it easy to customize and create HttpClient instances with the desired configurations.

Consuming HttpClientBuilder to perform network calls

We have the builder that we can use to get HttpClient, and with the help of HttpClient we can perform network calls.

To make our network call, we need a REST API. If you want to learn how to create RESTful APIs with Ktor, there’s a helpful tutorial you can watch here. But for now, you can find dummy REST APIs easily by searching on Google. I found one that we can use for this example.

Mapping JSON Response to Data Class

To properly map the response from the given URL, we’ll need the following data class. In this instance, I’ve utilized the @Serializable and @SerialName annotations, both of which are part of the kotlinx.serialization library we included in our project. These annotations play a crucial role in defining how the response is mapped to our data class.

Performing Network Call

We’ll execute a basic HTTP GET request using the HTTP client. In this context, I’ve established a MainViewModel where the call is being initiated.

The MainViewModel class extends the ViewModel class and takes an instance of HttpClient as a parameter. This class is responsible for handling user-related data and making HTTP requests.

  1. StateFlow for Users:
    • Inside the class, there’s a MutableStateFlow named _users that holds a list of UserResponse.User objects. This is essentially the data we want to observe and react to.
    • The users property is a public StateFlow derived from _users. It provides external access to the user data.
  2. Initialization:
    • In the init block, the getUsers function is called to initiate the process of fetching user data as soon as the MainViewModel is created.
  3. getUsers Function:
    • The getUsers function is a coroutine launched within the viewModelScope. This ensures that it operates within the lifecycle of the associated ViewModel.
    • It utilizes the injected httpClient to make an HTTP GET request.
    • The request is made to the “api/users” endpoint using the url function.
    • The response is of type UserResponse, and it represents the structure of the expected JSON response from the API.
  4. Updating StateFlow:
    • The obtained response.users (list of users) is assigned to _users.value, updating the StateFlow.
    • This triggers observers (such as UI components observing users) to react to the new user data.

In essence, the MainViewModel orchestrates the retrieval of user data from a specified API endpoint using the provided httpClient. The fetched data is then exposed through a StateFlow, allowing other components to observe and react to changes in the user data.

Consuming the Result in UI

Now that we’ve completed all the necessary steps, we have a list of users ready to be consumed and displayed on the UI. In this example, I’ve incorporated this user data consumption in the MainActivity.

Now, go ahead and execute your project, ensuring that you include the necessary internet permission in your manifest file. This step is crucial for enabling network connectivity.

Addressing Project’s Shortcomings

There are a couple of issues in this project that merit attention.

  • Firstly, the creation of a ViewModelFactory to supply the HttpClient instance introduces unnecessary boilerplate code. This can be alleviated by incorporating dependency injection.
  • Secondly, the tutorial skips handling the scenario where the API call fails for the sake of simplicity.

However, for a more comprehensive understanding, I recommend referring to my course “Architecting Excellence: A Deep Dive into Multi-Module Android Apps.” In that course, every aspect of this concern is thoroughly covered.

Concluding this post, I trust you found it enjoyable and insightful. If you encounter any issues, questions, or confusion, please feel free to leave your comments below. Crafting articles of this nature demands considerable effort, and your feedback is immensely valuable. If you believe this content has offered you valuable insights, I urge you to share this newfound knowledge with your friends. Your support not only acknowledges the effort invested but also helps in expanding our community of knowledge seekers. Thank you for your time and engagement!

Hi, my name is Belal Khan and I am a Google Developers Expert (GDE) for Android. The passion of teaching made me create this blog. If you are an Android Developer, or you are learning about Android Development, then I can help you a lot with Simplified Coding.

Expand Your Knowledge: Next Tutorial Picks

5 2 votes
Article Rating
Notify of

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Inline Feedbacks
View all comments
Would love your thoughts, please comment.x