一、前言:
我們在開發(fā)過程中,很可能會遇到這樣的需求,一個頁面中需要同時請求好幾個接口。
作用域學習:http://www.itdecent.cn/p/70f8373932b8
二、Kotlin協(xié)程處理并發(fā)
1、先模擬2個請求
suspend fun one(): Int {
delay(1500)
return 1
}
suspend fun two(): Int {
delay(1500)
return 2
}
兩個方法都是可掛起的方法,分別返回1和2
2、接口并發(fā)執(zhí)行
假如這兩個接口之間沒有聯系,我們想讓他們并發(fā)執(zhí)行的話,我們可以使用async和await配合使用。
代碼如下:
fun main() {
GlobalScope.launch {
/*measureTimeMillis返回給定的block代碼的執(zhí)行時間*/
val time = measureTimeMillis {
val sum = withContext(Dispatchers.IO) {
val one = async { one() }
val two = async { two() }
one.await() + two.await()
}
println("兩個方法返回值的和:${sum}")
}
println("執(zhí)行耗時:${time}")
}
println("----------------")
/*應為上面的協(xié)程代碼并不會阻塞掉線程,所以我們這里讓線程睡4秒,保證線程的存活,在實際的Android開發(fā)中無需這么做*/
Thread.sleep(4000)
}
下面我們來運行看看執(zhí)行結果:

總結:在協(xié)程作用域中請求使用async是同步執(zhí)行,await并發(fā)返回結果。
3、Kotlin協(xié)程處理多個耗時操作按順序執(zhí)行
假如你有這樣的需求,接口B的參數是接口A返回的結果,那這樣的話,使用協(xié)程依然能夠很簡潔的實現。
我們把兩個網絡請求方法稍微改動一下:
suspend fun one(): Int {
delay(1000)
return 1
}
suspend fun two(int: Int): Int {
delay(2000)
return 2 + int
}
方法two接收一個參數,該參數是由方法one返回的結果決定的
實現代碼如下:
fun main() {
GlobalScope.launch {
/*measureTimeMillis返回給定的block代碼的執(zhí)行時間*/
val time = measureTimeMillis {
val sum = withContext(Dispatchers.IO) {
val one = one()
val two = two(one)
one + two
}
println("兩個方法返回值的和:${sum}")
}
println("執(zhí)行耗時:${time}")
}
println("----------------")
/*應為上面的協(xié)程代碼并不會阻塞掉線程,所以我們這里讓線程睡4秒,保證線程的存活,在實際的Android開發(fā)中無需這么做*/
Thread.sleep(4000)
}

可以看到我們得到了想要的結果。
總結:在協(xié)程作用域中接口的執(zhí)行順序是串行的,one()執(zhí)行完,再執(zhí)行two()。
三、人工智能ChatGPT
1、Kotlin 協(xié)程請求,比如有1、2、3個請求,數據怎么一起返回?
在 Kotlin 中使用協(xié)程進行多個請求的并發(fā)處理可以使用 async 和 await 函數。以下是一個示例代碼:
import kotlinx.coroutines.*
suspend fun requestData(url: String): String {
// 發(fā)送網絡請求并返回數據
}
suspend fun main() {
val result = coroutineScope {
val request1 = async { requestData("http://example.com/api/1") }
val request2 = async { requestData("http://example.com/api/2") }
val request3 = async { requestData("http://example.com/api/3") }
"${request1.await()} ${request2.await()} ${request3.await()}"
}
println(result)
}
在上面的代碼中,async 函數用于并發(fā)發(fā)送請求,而 await 函數則用于等待請求的結果返回。在 coroutineScope 內部使用 async 函數創(chuàng)建了三個協(xié)程,它們分別發(fā)送了三個請求。通過 await 函數等待這三個請求的結果返回后,將它們拼接在一起并返回。
在這個例子中,我們使用了 coroutineScope 函數來創(chuàng)建一個協(xié)程作用域,這樣就可以在一個作用域中創(chuàng)建多個協(xié)程,并且等待它們全部完成后再返回結果。
2、Kotlin 協(xié)程請求,比如有1、2、3個請求,3要用2的返回值,2要用1的返回值,怎么請求?
在 Kotlin 中使用協(xié)程進行多個請求的并發(fā)處理,可以使用 async 和 await 函數。針對需要后續(xù)請求使用前面請求返回值的情況,可以使用 async 函數的 start 參數來控制協(xié)程的啟動時間。以下是一個示例代碼:
import kotlinx.coroutines.*
suspend fun requestData1(): Int {
// 發(fā)送網絡請求并返回數據
}
suspend fun requestData2(value: Int): String {
// 發(fā)送網絡請求并返回數據,使用前面請求的返回值
}
suspend fun requestData3(value: String): Boolean {
// 發(fā)送網絡請求并返回數據,使用前面請求的返回值
}
suspend fun main() {
val result = coroutineScope {
val request1 = async { requestData1() }
val request2 = async(start = CoroutineStart.LAZY) { requestData2(request1.await()) }
val request3 = async(start = CoroutineStart.LAZY) { requestData3(request2.await()) }
"${request1.await()} ${request2.await()} ${request3.await()}"
}
println(result)
}
在上面的代碼中,我們使用了 async 函數創(chuàng)建了三個協(xié)程。其中,第一個協(xié)程 request1 發(fā)送了第一個請求,并返回了一個 Int 類型的數據;第二個協(xié)程 request2 開啟了延遲啟動模式(start = CoroutineStart.LAZY),它會等待 request1 協(xié)程的結果返回后,再發(fā)送第二個請求,并返回一個 String 類型的數據;第三個協(xié)程 request3 同樣開啟了延遲啟動模式,它會等待 request2 協(xié)程的結果返回后,再發(fā)送第三個請求,并返回一個 Boolean 類型的數據。
在 coroutineScope 內部,我們通過 await 函數等待三個請求的結果返回,將它們拼接在一起并返回。
需要注意的是,使用延遲啟動模式的協(xié)程需要手動調用 await 函數來啟動,否則它們不會執(zhí)行。在上面的代碼中,我們在 request2 和 request3 協(xié)程中使用了 await 函數來手動啟動它們。
四、Kotlin協(xié)程項目實戰(zhàn)(MVVM框架中進行)
1、創(chuàng)建請求作用域
//作用域
val mainScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
2、同步并發(fā)請求(例如:A接口和B接口,返回結果組裝)
//同步并發(fā)請求
mainScope.launch{
val request1 = async {
Log.d("lyy", "執(zhí)行request1----開始:" + DateTimeHelper.format(Date(), "yyyy-MM-dd HH:mm:ss.SSS"))
apiService.getDiscoverData(map)
}
val request2 = async {
Log.d("lyy", "執(zhí)行request2----開始:" + DateTimeHelper.format(Date(), "yyyy-MM-dd HH:mm:ss.SSS"))
apiService.getDiscoverData(map)
}
val await1= request1.await()
val await2= request2.await()
//需要手動處理異常情況
mainDiscoverData.value = await1.data
responseDiscoverFailData.value = false
MyToash.Log("lyy","----request1:${await1.data.label?.get(0)?.recommend_id}")
MyToash.Log("lyy","----request2:${await2.data.label?.get(0)?.recommend_id}")
}
請求接口時間:
//請求接口時間
執(zhí)行request1----開始:2023-03-15 11:52:00.054
執(zhí)行request2----開始:2023-03-15 11:52:00.063
3、默認串行請求接口(例如:B接口需要A接口結果作為參數)
//默認串行請求接口
mainScope.launch{
Log.d("lyy", "執(zhí)行request1----開始:" + DateTimeHelper.format(Date(), "yyyy-MM-dd HH:mm:ss.SSS"))
val request1 = apiService.getDiscoverData(map)
Log.d("lyy", "執(zhí)行request2----開始:" + DateTimeHelper.format(Date(), "yyyy-MM-dd HH:mm:ss.SSS"))
val request2 = apiService.getDiscoverData(map)
//需要手動處理異常情況
mainDiscoverData.value = request1.data
responseDiscoverFailData.value = false
}
請求接口時間:
//請求接口時間
執(zhí)行request1----開始:2023-03-15 11:26:34.527
執(zhí)行request2----開始:2023-03-15 11:26:35.432
參考:https://blog.csdn.net/yuzhiqiang_1993/article/details/101022254