This Article Is Enough for Kotlin Coroutines

This article is enough for Kotlin coroutines solution


foreword
What are Kotlin coroutines and how to use them? How to use Retrofit? What are the advantages of Kotlin coroutines? I believe you will gain something after reading this article!
Basic use of coroutines
If we use coroutines, first we have to introduce development packages related to coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7-mpp-dev-11'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7-mpp-dev-11'

The above one is in the java environment, and the next one is in the android environment, which we all introduce here.
The simplest use of coroutines, we can use GlobalScope.launch to start a coroutine code as follows:
GlobalScope.launch {
Log.d(TAG, Thread.currentThread().name)
}

Kotlin coroutines.The result of running is as follows:



Kotlin coroutines.It means that this code runs in a sub-thread. Of course, we can pass parameters in launch to make it run in the main thread:
GlobalScope.launch(Dispatchers.Main) {
Log.d(TAG, Thread.currentThread().name)
}

In this way, the code inside runs in the main thread, so what is the coroutine? Simply put, a coroutine allows us to open a thread, which is a thread framework. Of course, in the actual project, we will not use the above method to start the coroutine. Don't worry, we'll go step by step~

Kotlin coroutines.What are the advantages of coroutines compared to threads?



Kotlin coroutines.The advantages of coroutines compared with threads, we will directly use an example to illustrate. For example, we are currently going to request the network, and then display the data after getting the data. Here we simulate two methods, namely, obtaining data for network requests and sending data Displayed on the UI, we define the method as follows:
/**
* Get information from server
*/
private fun getMessageFromNetwork(): String {
for (i in 0..1000000) {
//This simulates a time-consuming operation
}
var name = "Huanglinqing"
return name
}
/**
* Display information
* @message : message
*/
private fun showMessage(message: String) {
tvName.text = message
}

Kotlin coroutines. Since getMessage is a time-consuming operation, we put it in the child thread, and in Android, the UI update operation cannot be placed in the child thread, so we must put the showMessage method in the UI thread. Before we implemented this You can only execute the thread-cutting code yourself. The code is as follows
/**
* Get information from server
*/
private fun getMessageFromNetwork() {
for (i in 0..1000000) {
//This simulates a time-consuming operation
}
var name = "Huanglinqing"
runOnUiThread {
showMessage(name)
}

Execute the following code in onCreate:
Thread {
getMessageFromNetwork()
}.start()

This looks fine, but if the requirement is now changed to: request the first one to be displayed, and then request the second to be displayed, the code looks like this
private fun getMessageFromNetwork() {
for (i in 0..1000000) {
//This simulates a time-consuming operation
}
var name = "Huanglinqing"
runOnUiThread {
showMessage(name)
Thread{
getMessageFromNetwork1()
runOnUiThread{

}
}.start()
}
}

By analogy, we can think that if there are many requests, the first code structure will be ugly, and the second one will be messy when written, so coroutines can solve this problem very well. Let's look at using coroutines how to write.
First of all, for a time-consuming operation, we need to switch it to a background thread for execution. The withContext function can build a coroutine scope, which must be executed in a suspend function or coroutine. The suspend keyword is provided by kotlin for us. Keyword used to mark suspending functions. We modify the getMessageFromNetwork method as follows:
/**
* Get information from server
*/
private suspend fun getMessageFromNetwork(): String {
var name = ""
withContext(Dispatchers.IO) {
for (i in 0..1000000) {
//This simulates a time-consuming operation
}
name = "Huanglinqing1111"
}
return name
}

Write this directly in the coroutine in onCreate:
GlobalScope.launch(Dispatchers.Main) {
var name = getMessageFromNetwork()
showMessage(name)
}

The result of running is as follows:
If we have multiple requests, then add a few more
GlobalScope.launch(Dispatchers.Main) {
var name = getMessageFromNetwork()
showMessage(name)
var name1 = getMessageFromNetwork()
showMessage(name1)
var name2 = getMessageFromNetwork()
showMessage(name2)
}

In this way, getMessageFromNetwork is executed in the background, and showMessage is executed in the foreground, from this point of view.
What are the advantages of coroutines over threads?
1. Coroutines can help us automatically cut threads
2. Get rid of the problem of chained callbacks
How Retrofit uses coroutines
Since Retrofit 2.6.0, retrofit has automatically supported coroutines. Here we find an open api from "aggregated data"
Let's first look at how we used it before. First, define an interface in Apiservice as follows:
@GET("https://wanandroid.com/article/listproject/0/json")
fun queryData(): Call>

Add the following code to the activity:
var retrofit = Retrofit.Builder()
.baseUrl("http://v.juhe.cn/")
.addConverterFactory(GsonConverterFactory.create())
.build()
val apiService = retrofit.create(ApiService::class.java)
tvName.setOnClickListener {
apiService.queryData("top","04ea095cbea56775e2d1669713f34cc2")
.enqueue(object :Callback>{
override fun onFailure(call: Call>, t: Throwable) {
tvName.text = t.toString()
Log.d("网络请求错误", t.toString())
}
override fun onResponse(
call: Call>,
response: Response>
) {
tvName.text = response.code().toString()
}
})
}

Here we display the status code of the returned result on the view, and the running result is shown in the figure:
The above code does not seem to be a problem. If we use the mvp mode or something, it is convenient for a single responsibility, and it should be placed in a separate class, so that we need to add a callback to get the return result.
So how to use it in coroutines?
First, we add a function to ApiService, which is declared as a suspend function, and the type does not need to add Call
@GET("toutiao/index")
suspend fun queryDataKotlin(@Query("type") type: String?, @Query("key") key: String?): BaseReqData

The code in onCreate looks like this:
GlobalScope.launch(Dispatchers.Main) {
try {
var result = apiService.queryDataKotlin("top", "04ea095cbea56775e2d1669713f34cc2")
tvName.text = result.toString()
}catch(e:Exception){
tvName.text = e.toString()
}
}
That's right, it's that simple, there is no callback, because queryDataKotlin is a suspend function. When the suspend function is run, the coroutine will be in a waiting state. After returning the result, it will actively switch back to the main thread and execute the following method.
The function of try catch is equivalent to the callback of onFailure above. At this time, you may say, I will go! I also have to write try catch, which feels good. Don’t forget, another advantage of coroutines is that callbacks can be reduced. If there is still a success method or a failure method, then the callback logic is still used!

Coroutines improve efficiency
What efficiency can coroutines improve? Suppose, we now have two interface requests, and we need to wait until the results are displayed when both interfaces are requested. What if it was before, request interface 1 first, and then request the result after interface 1 has the result. 2, and the coroutine can do it, interface 1 and interface 2 are requested at the same time, and the results will be combined and displayed after the request is over. Here we request a unified interface to simulate requesting two different interfaces
GlobalScope.launch(Dispatchers.Main) {
try {
var result1 =
async { apiService.queryDataKotlin("top", "04ea095cbea56775e2d1669713f34cc2") }
var result2 =
async { apiService.queryDataKotlin("top", "04ea095cbea56775e2d1669713f34cc2") }
tvName.text = result1.await().toString() + " == " + result2.await().toString()+"interface2"
} catch (e: Exception) {
tvName.text = e.toString()
}
}

The result of running is as follows:
In this way, the two things that were supposed to be done in steps can be done at the same time. Of course, the efficiency can be improved. The async function must be called in the coroutine scope, a new sub-coroutine will be created, and a Deferred object will be returned. Call this The await method of the object can get the execution result.
How to use coroutines in online projects
There are many ways to create coroutines, including the GlobalScope.launch method we mentioned above, and the runBlocking method
GlobalScope.launch creates a top-level coroutine, and the coroutine created by runBlocking will block the thread until the code in the coroutine scope is executed, so the above. Neither method is recommended.
The coroutineScope function is a suspend function, it will inherit the external coroutine scope and create a sub-coroutine, which can only be called in the coroutine scope or the suspend function
The launch function must be in the scope of the coroutine to be called.
Having said so much, how do we change how to create coroutines in the project ?
We can directly create a CoroutineScope object as follows:
var coroutineScope = CoroutineScope(Dispatchers.Main)

coroutineScope.launch {
}

In this way, we have created a coroutine, which can be used according to the above method
If we make a network request in the coroutine when the page is opened, we also need to cancel the coroutine task when the page is destroyed to avoid unnecessary problems.
How to cancel a coroutine task
The coroutineScope can directly call the cancel method. If we use the GlobalScope.launch method, it will return a job object. We can use job.cancle to cancel the coroutine task.
Finally, the power of the coroutine is far more than the above
Using Jetpack's extension to kotlin in your project can make it easier to create and use coroutines.
as follows:
lifecycleScope.launch {

}

or
viewModelScope.launch {
}

Related Articles

Explore More Special Offers

  1. Short Message Service(SMS) & Mail Service

    50,000 email package starts as low as USD 1.99, 120 short messages start at only USD 1.00