Home Android & Kotlin Books Kotlin Coroutines by Tutorials

16
Networking With Coroutines Written by Luka Kordić

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Almost every Android app today has some form of network communication. User management, like login and registration, fetching news feed from your backend and uploading a profile picture are just a few of the most common tasks that require you to write networking code. That said, it’s important to keep your UI thread free to do other work while your app communicates with the server. Because networking code is quite common in Android apps, you want to make sure it is:

  • Performant - not blocking the main thread
  • Easy to read
  • Maintainable
  • Testable

In this chapter, you’ll see several ways of doing network calls via Retrofit library. First, you’ll make the standard API call with the callback-style approach and Retrofit’s Call as a return type. Then, you’ll replace that with a much more readable and shorter approach - using the power of coroutines and suspend functions.

Getting Started

For this chapter, you’ll use the same Disney API from previous chapters to obtain a list of characters and present it to the user. To start, open the starter project for this chapter and inspect the code. Focus on the following files:

  • DisneyApi.kt in data/networking package
  • DisneyApiService.kt in data/networking package
  • DisneyActivity.kt in ui/activity package

DisneyApi.kt is the interface to use when creating Retrofit instance. DisneyApiService.kt contains the implementation of the API calls defined in the interface. DisneyActivity.kt represents a simple screen with the basic RecyclerView setup for displaying a list of Disney characters.

Network Call With Callbacks

To check out the callback-style based implementation, start with DisneyApi.kt file. You’re going to use getCharacters, which looks like this:

@GET("characters")
fun getCharacters(): Call<CharactersResponse>
fun getCharacters(
  onError: (Throwable) -> Unit,
  onSuccess: (List<DisneyCharacter>) -> Unit
  ) {
  // Make an asynchronous request
  disneyApi.getCharacters().enqueue(object : Callback<CharactersResponse> {
    override fun onResponse(
      call: Call<CharactersResponse>,
      response: Response<CharactersResponse>
    ) {
      // Invoke onSuccess lambda when the results are ready
      val data = response.body()
      if (data == null) {
        onError(Throwable("No response"))
      } else {
        onSuccess(data.data)
      }
    }

    override fun onFailure(call: Call<CharactersResponse>, t: Throwable) {
      // Invoke onError if an error happens
      onError(t)
    }
  })
}

Coroutine-Powered Networking

To see how easy it is to implement coroutines for networking, and how it makes the code more understandable compared with callbacks or other mechanisms, you’re going to refactor the previous example to rely on coroutines. Go back to your DisneyApiService.kt and replace the getCharacters implementation with this one:

// 1
suspend fun getCharacters(): Result<CharactersResponse> = withContext(Dispatchers.IO) {
  try {
    // 2
    val data = disneyApi.getCharacters().execute().body()
    // 3
    if (data == null) {
      Result.failure(Throwable("No response"))
    } else {
      Result.success(data)
    }
  } catch (error: Throwable) {
    // 4 
    Result.failure(error)
  }
}
private fun fetchDisneyCharacters() {
    lifecycleScope.launch {
      apiService.getCharacters()
        .onSuccess { showResults(it.data) }
        .onFailure { showError(it) }
    }
  }

Retrofit Meets Coroutines

Here’s a quick recap of what you had to do to switch your API call to use coroutines:

@GET("characters?page=2")
suspend fun getCharactersSuspend(): CharactersResponse
suspend fun getCharacters(): Result<CharactersResponse> = kotlin.runCatching {
  disneyApi.getCharactersSuspend()
}

Key Points

  • Prefer Kotlin Coroutines over callback-style approach to make your networking code simple and more readable.
  • Mark your Retrofit methods with suspend and return the data model you need.
  • Retrofit will do the threading for you when you use suspend.
  • Make sure to catch any potential errors in the networking layer of the app.
  • If you need some metadata about the response, use Retrofit’s Response<T> as a return type.

Where to Go From Here?

That’s it for this chapter. It’s a short one, but that’s only because coroutines make networking on Android short and sweet! :]

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

© 2022 Razeware LLC

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.