Как дождаться окончания звонка, чтобы сделать еще один звонок? - PullRequest
1 голос
/ 14 марта 2019

Я использую RxJava, и я знаю о concat, и я думаю, это подходит мне, потому что я хочу завершить сначала весь первый вызов, а затем сделать второй, но я не знаю, какчтобы реализовать это.

У меня есть это сейчас:

private fun assignAllAnswersToQuestion(questionId: Long) {

        answerListCreated.forEach { assignAnswerToQuestion(questionId, it.id) }

    }

    private fun assignAnswerToQuestion(questionId: Long, answerId: Long) {
        disposable = questionService.addAnswerToQuestion(questionId,answerId,MyUtils.getAccessTokenFromLocalStorage(context = this))
        .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(
                {
                    result -> //Do nothing it should call the next one

                },
                { error -> toast(error.message.toString())}
            )
    }

Но потом, как только это будет закончено, все это forEach Я хотел бы сделать что-то вроде этого:

private fun assignAllAnswersToQuestion(questionId: Long) {

   answerListCreated.forEach { assignAnswerToQuestion(questionId, it.id) 
   anotherCallHere(questionId) //Do it when the first forEach is finished!!

}

Есть идеи?

Кроме того, есть ли способ сделать это с сопрограммами это?

Ответы [ 2 ]

1 голос
/ 14 марта 2019

Я думаю, вам нужно .map ваш список (answerListCreated) до списка Flowable с, а затем использовать Flowable.zip в этом списке.
zip используется для объединения результатов Flowable с в один результат. Поскольку вам не нужны эти результаты, мы их игнорируем.
После zip вы уверены, что все предыдущие Flowable s закончились, и вы можете .flatMap выполнить ваш следующий вызов (при условии, что anotherCallHere возвращает Flowable.

В конце концов, это будет что-то вроде:

val flowableList = answerListCreated.map { assignAnswerToQuestion(questionId, it.id) }

disposable = Flowable.zip(flowableList) { /* Ignoring results */ }
    .flatMap { anotherCallHere(questionId) }
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe {
        // ...
    }

Следует отметить, что в случае сбоя любого из вызовов произойдет сбой всей цепочки (будет вызываться onError).

0 голосов
/ 14 марта 2019

Я новичок в сопрограммах, но думаю, что могу ответить за них:

Вы можете использовать сопрограммы runBlocking {} для этого.

private fun assignAllAnswersToQuestion(questionId: Long) = launch {
    runBlocking {
        answerListCreated.forEach { assignAnswerToQuestion(questionId, it.id) }
    }
    anotherCallHere(questionId)
}

private fun assignAnswerToQuestion(questionId: Long, answerId: Long) = launch (Dispatchers.IO) {
    questionService.addAnswerToQuestion(
        questionId,
        answerId,
        MyUtils.getAccessTokenFromLocalStorage(context = this)
    )
}

launch {} возвращает объект Jobкоторая становится дочерней работой родительского сопрограммы.runBlocking {} будет блокировать до тех пор, пока все его дочерние задания не будут завершены (альтернатива - использовать запуск {} .join (), который будет иметь одинаковый эффект).

Обратите внимание, что обе функции обернули свой кодв блоке запуска {}.Чтобы иметь возможность вызывать метод запуска {}, вы, вероятно, захотите, чтобы ваш класс реализовал CoroutineScope

class MyActivityOrFragment: Activity(), CoroutineScope {
    lateinit var job = SupervisorJob()
    private val exceptionHandler =
        CoroutineExceptionHandler { _, error ->
            toast(error.message.toString()
        }
    override val coroutineContext = Dispatchers.Main + job + exceptionHandler

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        job = Job()
    }

    override fun onDestroy() {
        super.onDestroy()
        job.cancel()
    }

    ...
}

...