Naz
Naz

Reputation: 149

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)
}

Upvotes: 4

Views: 4547

Answers (1)

Andrei Tanana
Andrei Tanana

Reputation: 8442

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).

Upvotes: 10

Related Questions