Kotlin как сделать несколько запросов в очереди - PullRequest
4 голосов
/ 17 февраля 2020

У меня есть несколько запросов, каждый запрос возвращает 10 пунктов. Примерно так:

        var startIndex = 0
        var batchSize = 10
        var totoalCount = 50 
        var requestTimes = totoalCount/batchSize 
        for (index in 1..reqeustTimes) {
           client.request(url, "POST", startIndex) {
               completion(result.map {
                  //store in an array and append the returned items
               })
            startIndex += batchSize
        }

Но я хочу контролировать порядок, например, поместить запрос в очередь, один закончил запуск, следующий.

Как мне это сделать?

Спасибо!

РЕДАКТИРОВАТЬ

completion: ((Result<JsonObject>) -> Unit)? 

является лямбда-выражением.

РЕДАКТИРОВАТЬ:

Я могу сделать запрос один за другим, но сейчас проблема в том, что запрос не в порядке.

launch {   
          (1..parameter.totalSize/parameter.batchSize).asFlow()
                    .map { _ -> fetchItem(parameter)}.collect()
}

Ответы [ 2 ]

1 голос
/ 21 февраля 2020

Я получил решение от сопрограмм .

Сначала сделайте fetchItems функцией приостановки:

suspend fun fetchItems(paramter: Parameter) {}

Затем

var startIndex = 0
var batchSize = 10
var totoalCount = 50 
var requestTimes = totoalCount/batchSize 


launch {
            (1..requestTimes).asFlow()
                .map {
                    val p = parameter.copy(startIndex = it * 10)
                    fetchItems(p, completion)
                }.collect()
        }

Достаточно просто.

Или вы можете использовать другую версию запуска:

         launch {
            repeat(parameter.requestTimes) {
                val p = parameter.copy(startIndex = it * batchSize)
                requestContact(p, completion)
            }
        }

PS : 1. Для параметра попробуйте использовать свойства val для убедитесь, что это потокобезопасно.

Иногда вам может потребоваться отменить пакетные запросы.

Вот решение:

class Downloader: CoroutineScope by CoroutineScope(Dispatchers.Default) {

    fun destroy() {
        cancel()
    }

    fun startDownloder() {
        // add above launch in here.
    }
}

Тогда вы можете:

runBlocking  {
            val downloader = Downloader()
            downloader.startDownloder()
            delay(5000L) // this can be used just for debugging to see requests are really canceled
           // Cancel the requests
            downloader.destroy()
        }
1 голос
/ 17 февраля 2020

Вы можете использовать сопрограмму для этой цели,

Например:

// suspend fun main() = withContext(Dispatchers.Default) { // for production
fun main() = runBlocking { // for testing (single threaded)
    var startIndex = 0
    val batchSize = 10
    val totoalCount = 50
    var requestTimes = totoalCount / batchSize
    for (index in 1..requestTimes) {
        val result = request(startIndex)
        // do result.onSuccess{} here
        startIndex += batchSize
    }
}

suspend fun request(startIndex: Int) = suspendCoroutine<Result<JsonObject>> {cont ->
    client.fetchItems(startIndex) { cont.resume (it) }
}

ПРИМЕЧАНИЕ. Поскольку я не знаю, что такое тип fetchItems {it} в функции запроса я использовал suspendCoroutine<Result<JsonObject>>, изменив его на то, что возвращают ваши fetchItems

Поток будет приостановлен до завершения сопрограммы, и другая сопрограмма может легко занять этот поток, пока запрос не будет продолжение возобновлено. Так что это не похоже на блокировку потока или чего-либо (глупо):).

РЕДАКТИРОВАТЬ: см. https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/suspend-coroutine.html и https://discuss.kotlinlang.org/t/where-is-suspendcoroutine-supposed-to-be-used/11190/2

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...