Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin Coroutine Retrofit - Chain network calls

I'm trying to use Kotlin Coroutines + Retrofit to make my network calls, but my current implementation has two problems.

A) It only returns once my loop has completed.

B) it seems to wait for each call in my loop to complete before making the next one.

The API I'm interacting with requires me to make an initial fetch, returning an array of itemId's

[ 1234, 3456, 3456 ... ]

and for each item in the above response, fetch that item with id

{ id: 1234, "name": "banana" ... }

My current implementation is as follows, what am I doing wrong?

suspend operator fun invoke(feedType: String): NetworkResult<List<MyItem>> = withContext(Dispatchers.IO) {
    val itemList: MutableList< MyItem > = mutableListOf()
    val result = repository.fetchItems()
    when (result) {
        is NetworkResult.Success -> {
            itemList.addAll(result.data)
            for (i in itemList) {
                val emptyItem = result.data[i]
                val response = repository.fetchItem(emptyItem.id)

                when (response) {
                    is NetworkResult.Success -> {
                        val item = response.data
                        emptyItem.setProperties(item)
                    }
                }
            }
        }
        is NetworkResult.Error -> return@withContext result
    }
    return@withContext NetworkResult.Success(itemList)
}
like image 807
Naz Avatar asked Oct 17 '25 07:10

Naz


1 Answers

I would like to propose you to use async to process every item separately:

suspend operator fun invoke(feedType: String): NetworkResult<List<MyItem>> = withContext(Dispatchers.IO) {
    when (val result = repository.fetchItems()) { // 1
        is NetworkResult.Success -> {
            result.data
                .map { async { fetchItemData(it) } } // 2
                .awaitAll() // 3
            NetworkResult.Success(result.data)
        }
        is NetworkResult.Error -> result
    }
}

private suspend fun fetchItemData(item: MyItem) {
    val response = repository.fetchItem(item.id)
    if (response is NetworkResult.Success) {
        item.setProperties(response.data)
    }
}

In this code, at first, we make a call to fetchItems to get the items ids (1). Then we make a call to fetchItem for every item at the same time (2). It can be easily done with coroutines and async. Then we wait until all data will be fetched (3).

like image 181
Andrei Tanana Avatar answered Oct 19 '25 21:10

Andrei Tanana



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!