Kotlin Coroutines

65 阅读2分钟

article link: kotlin-coroutines

Dispatchers: Dispatchers help coroutines in deciding the thread on which the work has to be done. There are majorly three types of Dispatchers which are IO, Default, and Main. Dispatchers 是帮助协程决定在哪一个线程上执行任务, 主要有三种: IO, Default 和 Main

  1. IO: is used for doing the network and disk-related work (适合 网络请求 和 文件操作)
  2. Default: is used to do the CPU-intensive work (适合 密集型的 任务处理 )
  3. Main: is the UI thread of Android, default (UI渲染)

Dispatchers.Default

We should use Dispatchers.Default to perform CPU-intensive tasks.

Example use cases:

  • Doing heavy calculations like Matrix multiplications.
  • Doing any operations on a bigger list presentin the memory like sorting, filtering, searching, etc.
  • Applying the filter on the Bitmap present in the memory, NOT by reading the image file present on the disk.
  • Parsing the JSON available in the memory, NOT by reading the JSON file present on the disk.
  • Scaling the bitmap already present in the memory, NOT by reading the image file present on the disk.
  • Any operations on the bitmap that are already present in the memory, NOT by reading the image file present on the disk.

Dispatchers.IO

We should use Dispatchers.IO to perform disk or network I/O-related tasks.

Example use cases:

  • Any network operations like making a network call.
  • Downloading a file from the server.
  • file/database operate
    • Moving a file from one location to another on disk.
    • Reading from a file.
    • Writing to a file.
    • Making a database query.
    • Loading the Shared Preferences.

Dispatchers.Main

We should use Dispatchers.Main to run a coroutine on the main thread of Android. We all know where we use the main thread of Android. Mainly at the places where we interact with the UI and perform small tasks.

Example use cases:

  • Performing UI-related tasks.
  • Any small tasks like any operations on a smaller list present in the memory like sorting, filtering, searching, etc.

Dispatchers.Unconfined

It does not change the thread. When it is started, it runs on the thread on which it was started. If it is resumed, it runs on the thread that resumed it.

  • suspend: Suspend function is a function that could be started, paused, and resume.

The difference is that the launch{} returns a Job and does not carry any resulting value whereas the async{} returns an instance of Deferred<T>, which has an await() function that returns the result of the coroutine like we have future in Java in which we do future.get() to get the result.

withContext does not create a new coroutine, it only shifts the context of the existing coroutine and it's a suspend function whereas launch and async create a new coroutine and they are not suspend functions.

The thumb-rules:

  • Both the launch and async are used to launch a coroutine. This enables us to do tasks in parallel.
  • async can be used to get the result that is not possible with the launch.
  • withContext does not launch a coroutine and it is just a suspend function used for shifting the context of the existing coroutine.

Scope:

  1. GlobalScope
  2. lifyCycleScope
  3. viewModelScope

This is how supervisorScope helps.

Conclusion:

  • While NOT using async, we can go ahead with the try-catch or the CoroutineExceptionHandler and achieve anything based on our use cases.

  • While using async, in addition to try-catch, we have two options: coroutineScope and supervisorScope.

  • With async, use supervisorScope with the individual try-catch for each task, when you want to continue with other tasks if one or some of them have failed.

  • With async, use coroutineScope with the top-level try-catch, when you do NOT want to continue with other tasks if any of them have failed.