Android協(xié)程中同時請求多個網絡接口

一、前言:

我們在開發(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í)行結果:

圖片.png

總結:在協(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)
}
圖片.png

可以看到我們得到了想要的結果。

總結:在協(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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容