Tag

Coroutines basics

Browsing

In this post, we will learn exception handling in coroutines. Later on, we will know how to handle exceptions in a sequential program.

In coroutine, exception behavior depends on coroutines builder. So we already know that we have to two coroutines builders. We have launch and async. launch generates a job and async will generate a deferred that will give us a value. So based on that the behavior changes slightly.

Exception behaviour with launch

So for launch, As you know launch creates a job hierarchy. So exceptions will propagate instantly through the parent-child hierarchy and will immediately cause jobs to fail. So there is no delay and no way to catch it automatically. So what we need to do, we need to use try-catch inside the launch or we have a structure called an exception handler. So the summary of this is below

  • Propagates through the parent-child hierarchy
  • The exception will be thrown immediately and jobs will fail
  • use try-catch or an exception handler

In sort, launch automatically generates the exception and causes all the jobs to fail in the exception hierarchy. In coroutines, you won’t see the exceptions straight away. you will see the exception when you try to actually use the job or coroutines in the main thread. So if you call join on the job you will automatically join into main thread and then you will see the exception.

Behaviour with async

The async is slightly different. So async means we don’t have a hierarchy we just have the outcome. So the exception is deferred, and it will not be shown until the result is consumed. So if we call wait then we will see the exception. If we never call wait we will never see the exception. So what we need to do in this case is use the try-catch when we are calling await call. In sort we can say

  • Exceptions are deferred until the result is consumed
  • If the result is not consumed, the exception is never thrown
  • try-catch in the coroutine or in the await() call

So the difference is the launch propagated the exception through the job hierarchy immediately and kill the jobs. The async will only show the exception when you call await().

Exception handling in launch

Now we have a way to handle exceptions in launch. In coroutines we have a class named is CoroutineExceptionHandler

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        runBlocking {
            val myHandler = CoroutineExceptionHandler {coroutineContext, throwable ->
                Log.e(TAG,"Exception handled: ${throwable.localizedMessage}")
            }

            val job = GlobalScope.launch(myHandler) {
                Log.e(TAG,"Throwing exception from job")
                throw IndexOutOfBoundsException("exception in coroutine")
            }
            job.join()

            val deferred = GlobalScope.async {
                Log.e(TAG,"Throwing exception from async")
                throw ArithmeticException("exception from async")
            }

            try {
                deferred.await()
            } catch (e: java.lang.ArithmeticException) {
                Log.e(TAG,"Caught ArithmeticException ${e.localizedMessage}")
            }
        }
    }
}

Output

 E/MainActivity: Throwing exception from job
 E/MainActivity: Exception handled: exception in coroutine
 E/MainActivity: Throwing exception from async
 E/MainActivity: Caught ArithmeticException exception from async

Conclusion

In this post, we learned how to handle exceptions in coroutines. I have used this exception handling concept in the retrofit example. I hope it’s helpful for you, Help me by sharing this post with all your friends who learning android app development.

Estimated reading time: 3 minutes

In this coroutines withContext example and we’ll see how we can change context easily in Coroutines. We’ll learn different ways to switch coroutine contexts also. In android aspects will see how to can switch the context main thread to another threads. So let’s started.

Uses of withContext

A function that is very commonly used in coroutines is withContext. Basically, withContext is allowed us to easily change context. It means It easily switches between dispatchers.

Suppose in an android application we have some heavy processing that we need to do. So we will do that in the Default Dispatchers then when the outcome completed then we want to switch to the Main Dispatchers in order to publish to display outcome on the UI. So we need a way to easily switch between context and the best way to do that is the withContext function. Because it’s very very lightweight.

Example of withContext

So let take a example see the below code

package com.asyncawaitexamplecoroutine

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        runBlocking {
            launch(Dispatchers.Default) {
                Log.d(TAG,"First context: $coroutineContext")
                // default context
                withContext(Dispatchers.IO) {
                    Log.d(TAG,"Second context: $coroutineContext")
                    // IO context
                }
                Log.d(TAG,"Third context: $coroutineContext")
                // back to default context
            }
        }
    }
}

In this code, first I’m going to launch a coroutine in the default dispatcher. and I’m gonna log coroutineContext. So simply I logging out the context that we have. Then I’m gonna switch dispatchers to IO dispatcher. So using withContext(Dispatchers.IO) I’m gonna log the second context here. So once that is finished, so I’m gonna go back to my first context. So let log the coroutineContext again.

So I’m starting a coroutine in default context then I’m switching to IO and then I’m coming back to original. So let’s go head and run the code and see the output that we get from the LOGCAT.

Output

 D/MainActivity: First context: [StandaloneCoroutine{Active}@45522db, Dispatchers.Default]
 D/MainActivity: Second context: [DispatchedCoroutine{Active}@940c178, Dispatchers.IO]
 D/MainActivity: Third context: [StandaloneCoroutine{Active}@45522db, Dispatchers.Default]

Do we have our first context which is standalone coroutine whatever the name is system has given it. Then we are switching context. so we can that we have different Id(940c178) here.

That mainly I just want to show you the different ID that we get. Here is @45522db, @940c178, @45522db. So when we finish there we’re going back to same context that we have initially.

So basically it’s a very lightweight way to switch between context depending on type of functionality, type of processing that we need to do.

Conclusion

That all, in this blog we have learned coroutines withContext example in Kotlin android.  I hope it’s helpful for you. Keep reading 🙂

In this blog, I’ll show you uses of async and await function in coroutine. We’ll learn async and await coroutine functions with example. So let’s started.

Objective

The async is basically another way to start a Coroutine. Sometimes when you start a coroutine, you might need a value to be return from that coroutine back to the thread that launched it. So async just like launch, except it return a result.

Now the results, obviously since it’s returning in parallel, It can not return immediately. so think about an operation like network communication might have undetermined delay. But we still want to have that resolved that outcome at some point. So what async does, is return a result in the form of a deferred.

So deferred is basically promise that at the some point we will be able to get result but it’s not available right now. So it’s a future promise of a value.

async function

So this question is when we actually need the value, we have the await function. Important things is, this is a blocking call. It done on purpose obviously because at certain points we do need the value we can not proceed without it. So we have to wait for that value to be available.

So either the value is available straight away which is return immediately or If in value is not available it will pause the current thread until it is. So you can say If the value is available, it will return immediately or If the value is not available, it will pause the thread until it is, as simple as that. For achieving this functionality we have await function in coroutine.

How use await function

It a quite simple, so let say we have one suspended function that gives a random integer number. Now would have aync coroutine. So we have a GlobalScope.aysnc just like below. This will launch a coroutine that simply return call the suspended function.

suspend fun getRandom() = Random.nextInt(1000)

val valueDeferred = GlobalScope.async { getRandom() }
… // Do some processing here
val finalValue = valueDeferred.await( )

So it will give us a deferred. So this is the object of deferred then we do whatever processing we need in that program. Then we actually need the value we have to await() function. So this will pause the execution until the value is available for our main program. So we are simply waiting for a value to be available.

Example of async and await

Let’s take one example for better understanding. Let suppose you want to call a APIs right. For calling that API you might need some auth token. For example you might need API key and Access Token for calling API. It not a useful or a practical example but explain async concept, Its perfect.

So here I simply creating a runBlocking. and define 3 functions. these are below.

package com.asyncawaitexamplecoroutine

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import kotlin.random.Random

class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "MainActivity"
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        runBlocking {
            val accessTokenDeferred = async { getAccessToken() }
            val apiKeyDeferred = async { getApiKey() }

            Log.i(TAG,"Doing some processing here")
            delay(500L)
            Log.i(TAG,"Waiting for values")

            val firstValue = accessTokenDeferred.await()
            val secondValue = apiKeyDeferred.await()

            textView.append("Access Token -> $firstValue \n")
            textView.append("API Key  -> $secondValue \n")
            textView.append(" User Details -> " + getUserDetails(firstValue,secondValue) )

        }
    }
    private suspend fun getAccessToken(): String {
        delay(1000L)
        val value = "ffe20d1e-bb7d-48c6-95a4-7d0f1fde26ab"
        Log.i(TAG,"Returning AccessToken $value")
        return value
    }

    private suspend fun getApiKey(): String {
        delay(2000L)
        val value = "ca6ee68b-73b8-41e1-8920-d20e349e36b6"
        Log.i(TAG,"Returning API key $value")
        return value
    }
    private suspend fun getUserDetails(accessToken:String, apiKey:String): String {
        delay(2000L)
        Log.i(TAG, " Access Token -> $accessToken API key ->$apiKey")
        val value = " Morris Kushwaha"
        Log.i(TAG,"Returning user details $value")
        return value
    }
}

It’s pretty straight forward, getAccessToken() and getApiKey() is aysnc in scope of run blocking. After that will call getUserDetails() function. In this function we simply logging access token and api and returning a value. So Important things is we are waiting a result from the first coroutine which will take 1 second.

Then second value is going to be deferred and it taking 2 second. After this simply calling userDetails function, that all. Let run this code and see this output

Output

I/MainActivity: Doing some processing here
I/MainActivity: Waiting for values
I/MainActivity: Returning AccessToken ffe20d1e-bb7d-48c6-95a4-7d0f1fde26ab
I/MainActivity: Returning API key ca6ee68b-73b8-41e1-8920-d20e349e36b6
I/MainActivity:  Access Token -> ffe20d1e-bb7d-48c6-95a4-7d0f1fde26ab API key ->ca6ee68b-73b8-41e1-8920-d20e349e36b6
I/MainActivity: Returning user details  Morris Kushwaha

So in logcat we get are Doing some processing here first after that Waiting for values. And getting AccessToken and after two second API key and finally Returning user details.

Conclusion

So basically async is a way for us to retrieve values from Coroutine. That all, so in this coroutine async and await example we’ll learned how we’ll make async call using Coroutine in android. I hope it’s helpful for you, Help me by sharing this post with all your friends who learning android app development.

FAQ

Coroutine related article

In this blog, we will learn how to use retrofit with coroutines Kotlin in android application, with the help of an example. So we are actually building an application in android using Coroutines, Retrofit and MVVM, and so on. So lets started.

Objectives

Basically, the purpose of the project is to get the list of users information from the endpoints and display it to users in RecyclerView. I’m listing them below of these are objectives of this Retrofit coroutines example blog.

  • Get a list of user’s info from an endpoint using REST API. Basically
  • Use coroutines with Retrofit and MVVM
  • Display the user’s info in a RecyclerView

So the main idea is to show you, how you can build a professional application using a proper architecture with Retrofit and using coroutines to get some information from a webserver. so that is what we are building.

Requirements

Now, there are some requirements for this retrofit coroutines example app. These are listed below

  • Android knowledge
  • Retrofit
  • MVVM

So idea is, I’m not going to details of these, you have to basic idea of these items. You should know how retrofit works with MVVM. I’m going to focus, this example on coroutines that work with Retrofit and MVVM.

All right guys, so lets started quickly with this example app. Open AndroidStudio and create a new android project with some template.

Setting up the project

Let wait for sync of project, that recently you created. And first of all let’s add internet permission in AndroidManifest that is obvious, Because we are communicating with backend APIs. So we do need that

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

All right then next step is we have to add below dependency in app build.gradle.

  • RecyclerView
  • Glide
  • Retrofit
  • Lifecycle extensions
  • Coroutines
    // RecyclerView dependency
    implementation "androidx.recyclerview:recyclerview:1.1.0"
    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
    // Glide dependency
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    // Retrofit dependency
    implementation 'com.squareup.retrofit2:retrofit:2.7.1'
    implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
    // Lifecycle dependency
    implementation 'android.arch.lifecycle:extensions:1.1.1'
    // Coroutines dependency
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'

Backend API Endpoint and JSON

So first of all, we require a REST API, that we have to consume in this project. You can use whatever you required. For now, I’m consuming this URL and json response is

{
  "page": 1,
  "per_page": 6,
  "total": 12,
  "total_pages": 2,
  "data": [
    {
      "id": 1,
      "email": "george.bluth@reqres.in",
      "first_name": "George",
      "last_name": "Bluth",
      "avatar": "https://reqres.in/img/faces/1-image.jpg"
    },
    {
      "id": 2,
      "email": "janet.weaver@reqres.in",
      "first_name": "Janet",
      "last_name": "Weaver",
      "avatar": "https://reqres.in/img/faces/2-image.jpg"
    },
    {
      "id": 3,
      "email": "emma.wong@reqres.in",
      "first_name": "Emma",
      "last_name": "Wong",
      "avatar": "https://reqres.in/img/faces/3-image.jpg"
    }
    .
    .
    .
  ]
}

Create user Model

Now, we are following the MVVM design pattern in this coroutines example. So I’m creating a data class for parsing above JSON resonse. Let create a data class named is UserList.kt

package com.retrofitcoroutines.example.model

import com.google.gson.annotations.SerializedName

data class UserList(
    @SerializedName("page") val page: Int,
    @SerializedName("per_page") val per_page: Int,
    @SerializedName("total") val total: Int,
    @SerializedName("total_pages") val total_pages: Int,
    @SerializedName("data") val data: List<User>
)
 

Let’s create another data class named User.kt

package com.retrofitcoroutines.example.model

import com.google.gson.annotations.SerializedName

data class User(
    @SerializedName("id") val id : Int,
    @SerializedName("email") val email : String,
    @SerializedName("first_name") val first_name : String,
    @SerializedName("last_name") val last_name : String,
    @SerializedName("avatar") val avatar : String
)

Update the activity_main.xml

Now in main_activity has below layout, So we have a RecyclerView, then TextView in case of error, we can display a message. And we have a ProgressBar, so user know that is something is going in background. So its quite simple you know. So there are 3 element and we’re going to hide to show these element.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".view.MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/usersList"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/listError"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        android:gravity="center"
        tools:text="Error"
        android:textColor="#FA1302"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ProgressBar
        android:id="@+id/loadingView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout> 

Create a ViewModel

Let create a ViewModel named is ListViewModel. Here we simply fetching user list from backend server and passes that data to our MutableLiveData. Apart from this, we have a load error which generates an error message in case of API failure. and we have a loading MutableLiveData(), That let us know there is something happens in background.

package com.retrofitcoroutines.example.viewmodel

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.retrofitcoroutines.example.model.User
import com.retrofitcoroutines.example.remote.UserService
import kotlinx.coroutines.*

class ListViewModel : ViewModel() {

    val userService = UserService().getUsersService()
    var job: Job? = null
    val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
        onError("Exception handled: ${throwable.localizedMessage}")
    }

    val users = MutableLiveData<List<User>>()
    val usersLoadError = MutableLiveData<String?>()
    val loading = MutableLiveData<Boolean>()

    fun refresh() {
        fetchUsers()
    }

    private fun fetchUsers() {
        loading.value = true
        job = CoroutineScope(Dispatchers.IO + exceptionHandler).launch {
            val response = userService.getUsers()
            withContext(Dispatchers.Main) {
                if (response.isSuccessful) {
                    users.value = response.body()?.data
                    usersLoadError.value = null
                    loading.value = false
                } else {
                    onError("Error : ${response.message()} ")
                }
            }
        }
        usersLoadError.value = ""
        loading.value = false
    }

    private fun onError(message: String) {
        usersLoadError.value = message
        loading.value = false
    }

    override fun onCleared() {
        super.onCleared()
        job?.cancel()
    }

} 

Connect ListViewModel to MainActivity

In the MainActivity we are instantiating the ListViewModel. Then we simply set up our RecycleView, Using a UserAdapter, That we’ll create below of the code, and then we are observing the ViewModel, which simply connecting Livedata from the ViewModel and proceeding to update the interface based on the information that we received. So all is that we need to do.

package com.retrofitcoroutines.example.view

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager
import com.retrofitcoroutines.example.R
import com.retrofitcoroutines.example.viewmodel.ListViewModel
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    lateinit var viewModel: ListViewModel
    private val userListAdapter = UserListAdapter(arrayListOf())

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewModel = ViewModelProviders.of(this).get(ListViewModel::class.java)
        viewModel.refresh()

        usersList.apply {
            layoutManager = LinearLayoutManager(context)
            adapter = userListAdapter
        }

        observeViewModel()
    }
    private fun observeViewModel() {
        viewModel.users.observe(this, Observer {countries ->
            countries?.let {
                usersList.visibility = View.VISIBLE
                userListAdapter.updateCountries(it) }
        })

        viewModel.usersLoadError.observe(this, Observer { isError ->
            listError.visibility = if(isError == "") View.GONE else View.VISIBLE
        })

        viewModel.loading.observe(this, Observer { isLoading ->
            isLoading?.let {
                loadingView.visibility = if(it) View.VISIBLE else View.GONE
                if(it) {
                    listError.visibility = View.GONE
                    usersList.visibility = View.GONE
                }
            }
        })
    }
}

Now create UserListAdapter

Simply create a RecyclerView Adapter and attached the user_item view to recycler as usual. The only different thing here is the extension function for ImageView to load the image which allows us to loan an image on ImageView based on the URL we have.

package com.retrofitcoroutines.example.view

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.retrofitcoroutines.example.R
import com.retrofitcoroutines.example.model.User
import com.retrofitcoroutines.example.utils.loadImage
import kotlinx.android.synthetic.main.item_user.view.*

class UserListAdapter(var users: ArrayList<User>): RecyclerView.Adapter<UserListAdapter.UserViewHolder>() {

    fun updateCountries(newUsers: List<User>) {
        users.clear()
        users.addAll(newUsers)
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(parent: ViewGroup, p1: Int) = UserViewHolder(
        LayoutInflater.from(parent.context).inflate(R.layout.item_user, parent, false)
    )

    override fun getItemCount() = users.size

    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        holder.bind(users[position])
    }

    class UserViewHolder(view: View): RecyclerView.ViewHolder(view) {

        private val imageView = view.userAvatar
        private val userName = view.userFullName
        private val userEmail = view.userEmail


        fun bind(user: User) {
            userName.text = user.first_name + " "+ user.last_name
            userEmail.text = user.email
            imageView.loadImage(user.avatar)
        }
    }
}

Here is item_user.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp"
    android:background="#E4DDF3">

    <ImageView
        android:id="@+id/userAvatar"
        android:layout_width="80dp"
        android:layout_height="80dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/ic_launcher_round" />

    <TextView
        android:id="@+id/userFullName"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:textColor="@color/colorPrimaryDark"
        android:textSize="18sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/userAvatar"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Morris" />

    <TextView
        android:id="@+id/userEmail"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="16dp"
        tools:text="morris@androidwave.com"
        android:textSize="16sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/userAvatar"
        app:layout_constraintTop_toBottomOf="@+id/userFullName" />
</androidx.constraintlayout.widget.ConstraintLayout>

Write a extension function for ImageView

Here I have created a new package named is utils and writes below extension function.

package com.retrofitcoroutines.example.utils

import android.widget.ImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.retrofitcoroutines.example.R

fun ImageView.loadImage(uri: String?) {
    val options = RequestOptions()
        .error(R.mipmap.ic_launcher_round)
    Glide.with(this.context)
        .setDefaultRequestOptions(options)
        .load(uri)
        .into(this)
}
  

That all about UI let setup Retrofit and connect it with project.

Setting up Retrofit

Let create a retrofit interface. Here I’m gonna set up a GET function for Retrofit. Inside this interface create a suspending function like below. It simply returns us a Response.

package com.retrofitcoroutines.example.remote

import com.retrofitcoroutines.example.model.UserList
import retrofit2.Response
import retrofit2.http.GET

interface UserApi {

    @GET("users")
    suspend fun getUsers(): Response<UserList>

} 

Create a UsersService

In this class, first of I have created a variable here is BASE_URL. After that I have created a function named is getUsersService() that simply returns UserApi that we just defined earlier.

package com.retrofitcoroutines.example.remote

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

class UserService {
    
    private val BASE_URL = "https://reqres.in/api/";
    fun getUsersService(): UserApi{
       return Retrofit.Builder()
           .baseUrl(BASE_URL)
           .addConverterFactory(GsonConverterFactory.create())
           .build()
           .create(UserApi::class.java)
    }
}

That all done, let’s go ahead and run the code and see if it works. It’s working so we have all users that return from APIs in the context of coroutines. Basically, in this example, we have two coroutines because first, we are calling with Dispatchers.IO and finally we are calling Dispatchers.Main. So way we can update UI in main. thread. That code I already added in ViewModel, for reference I adding again

CoroutineScope(Dispatchers.IO + exceptionHandler).launch {
            val response = userService.getUsers()
            withContext(Dispatchers.Main) {
                if (response.isSuccessful) {
                    users.value = response.body()?.data
                    usersLoadError.value = null
                    loading.value = false
                } else {
                    onError("Error : ${response.message()} ")
                }
            }
        } 

Conclusion

So that is it, So we learned how to use Retrofit with coroutines in Kotlin| Android.  I hope it’s helpful for you, Help me by sharing this post with all your friends who learning android app development.

Download Source Code

Retrofit coroutines error handling

will publish a complete article on that, For now you can follow this article

Retrofit with coroutines

This is a sample app thats created. Please follow this article only

In this blog, we will learn suspending functions in a coroutine. I will show you how it works in coroutine android. What needs of these in a coroutine, etc. How they make callbacks seamless. So let’s started.

What is suspending functions

The idea behind suspending functions is quite easy. It simply a function that can be run in a coroutine. In simple words, a functions that can be run in a coroutine, and the main advantage I would say of suspending functions is that they make callbacks seamless.

Need of suspending functions

Actually In coroutine, If you try to access a function from coroutine you’ll get an error unless you make it a suspending function

Suspending functions example

let take a very basic example of suspending functions and understand how it makes developer life easier. So let started

In this example, I’m going to use the function named composeMessage() and one variable named count that equal to zero. So using this variable we simply track the number of calls to suspend the function. Let see the improvements things is the count (variables) is part of our main application. However, suspending functions composeMessage() will be part of Coroutine. Here is how easy it is to synchronize between our main thread and a Coroutine.

import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

var count = 0

fun main() {
    
 }

suspend fun composeMessage() {
    delay(500L)
    println("Android!")
    count++
}

Create improveMessage()

Let’s go ahead and create another function let say improveMessage(). This function also does kind of the same things. So here is delay is 1 second and simply println a message somethings like below.

suspend fun improveMessage() {
    delay(1000L)
    println("Suspend functions are cool")
    count++
}

Call functions in main thread

Now in our main program, let go head and launch these two coroutine just like below.

  import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

var count = 0

fun main() {
    GlobalScope.launch { composeMessage() }
    GlobalScope.launch { improveMessage() }
    print("Hi, ")
    Thread.sleep(2000L)
    println("There have been $count calls so far")
}

suspend fun composeMessage() {
    delay(500L)
    println("Android!")
    count++
}

suspend fun improveMessage() {
    delay(1000L)
    println("Suspend functions are cool")
    count++
}

Output

Now let run the programme and the expected out is below.

Hi, Android!
Suspend functions are cool
There have been 2 calls so far

So in console, we are getting Hi, half a second later. We are getting the Android! . Then we are getting a second message from improveMessage() function. And then we are checking the variable count. An important thing we are accessing that variable in the main thread that has been updated by the Coroutine. So this is how synchronization works. It is very easy to update functions or variables in the main thread from the Coroutine.

Conclusion

It’s not a very complicated fictionality and it’s probably not very useful in a real-world situation. But I’m sure it does highlight how we can run a function from a Coroutine. also importantly how we can update local variables from a Coroutine.

I hope this article helps you a lot, I would like to suggest you read our coroutines series. 

In this blog, let’s briefly discuss what Coroutines, This blog dedicated to beginners, they can learn the basic concept of coroutines, Once you understand these concepts of coroutines. You can become a master Coroutines.

Why we should use coroutines

Very first let understand why we should Coroutines an instance of thread. What is the very basic difference between thread and Coroutines? and why we want to use it instance on Thread. So let started

Thread are resource intensive

So the main problem with threads is it very resource-intensive. So it takes a lot of resources to start a thread, stop a thread, coordinate between threads, and so on. Meanwhile, Coroutines are lightweight threads Infect is very very lightweight threads.

Coroutines are lightweight threads

So we have a program where we start about millions of Coroutines and no problem in memory. If you try to start maybe a thousand threads your program will run out of memory will crash. But Coroutines are very very lightweight so you can start as many as you like with no overhead with no problem.

Ok so basically Coroutines to use pulls a thread pool is, let’s think about it as a bunch of thread that you can use whenever you like. So you have a small Coroutines which small unit of executions. Then you assign it to as thread. When the Coroutines is finishes the thread is put back in the thread pool ready to reuse by another Coroutines that need it.

Okay so they reuse threads they use lightweight functionality so you can start as many as you like with absolutely no impact on performance

Simplify async code, callback and synchronisation

Now these simplify greatly async code, So callback and synchronization are very very easy to use in Coroutines and actually they make parallel programming look very likes of sequential programming

So you can start a Coroutines code and immediately access variables and methods in your program without any overhead. And that is how easy it is to do callback from a Coroutines to your program and synchronization is also very useful, just you have 2 or 3 methods that you to synchronize between Coroutines without any overhead.

Wheres thread is very complicated and if you’ve ever worked with the thread you know what headache they can be especially when you start a lot of them need a synchronization between them.

Simple syntax

Coroutines have very very simple common syntax. So they have few concept that we will discuss in this blog, that fit together very nicely and Once you understand those concept they are very easy to use to start Coroutines and execute code in parallel. Now they can pause and resume at any time and a coroutines is not bound to a thread.

A thread simply place to execute the coroutines but the coroutines itself can be stoped at any time and restarted at any time.

So In that way they are very light weight and can be reused as many times as you like.

Coroutines basic concept

Now let go through a basic concept of Coroutines and here I’m going to list them and the upcoming article we’re going through them one by one and see the implementation with example. So let started

Scope

So the first idea is a scope. The scope is what creates and runs coroutines. It provides life cycle event so things like pausing a coroutine stopping, cancelling a coroutine, is handled by a scope.

Context

Now the context is a concept that is very tied to the scope. So the scope itself provides a context and The Context is simply the state of coroutine. Basically, It provides some variable some functionality that you can use in your coroutine. So that is a context the scope and context are very tightly tied together.

Suspending functions

Suspending function are basically functions that can be run in a coroutine or can be suspended as we call them. So basically they provide functionality that you use to run in parallel that you want o run in parallel.

Jobs

So next stuff we have jobs. Now a job is basically a handle on a coroutine and you can use a job to access the lifecycle methods of a coroutine. Okay so when you create a coroutine in a certain way which we will see in upcoming articles cancel the coroutine

You will create a job and job can we used to let say cancel the coroutine, If you choose later on next up we have a deferred which is basically a call team that returns a result.

Deferred

The next thing we have deferred is basically a call team that returns a result but sends a coroutine run in parallel. You can not return the result immediately. The result can only be only returned when the coroutine finishes its execution.

So that means we need deferred which is a future result of a coroutine and what you can do with a deferred, basically tell the program to wait for the outcome of that coroutine. when you are at a point where you need that result.

Dispatchers

Next, we dispatchers, which simply says that dispatchers manage a certain number of threads, and whenever a coroutine needs to run, it will assign it to a thread and run in time that particular thread.

So dispatcher we have just a few of them that are more or less suited for certain tasks that we will discuss in this post.

Error handling

Error handling kind of self-explanatory. It basically provides a way to handle any errors that might come up in a coroutine.

Conclusion

So that’s it these are major concepts of the coroutine. I the blog we’ll discuss these concepts in detail one by one. Once you understand the basics idea of coroutines. You can easily play around will all these concepts to give you the functionality that you require.

Estimated reading time: 5 minutes

Exit mobile version