How to wait until a bunch of calls ends to make another call

53
March 15, 2019, at 05:40 AM

I'm using RxJava and I know about concat, and I guess it does fit to me, because I want to finish first all of first call and then do the second one but I don't know how to implement it.

I have this from now :

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

But then, once this is finished all of this forEach I'd like to do something like this :

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

Any idea?

Also, is a way to do it with coroutines this?

Answer 1

I think you have to .map your list (answerListCreated) to a list of Flowables, and then use Flowable.concat on this list.
Something like:

val flowableList = answerListCreated.map { assignAnswerToQuestion(questionId, it.id) }
disposable = Flowable.concat(flowableList)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe { 
                    // ...
                }
Answer 2

I'm new to coroutines but I think I can answer for them:

You can use coroutines runBlocking {} for this.

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 {} returns a Job object which becomes a child job of the parent coroutine. runBlocking {} will block until all its child jobs have finished, (an alternative is to use launch {}.join() which will have the same affect).

Note that I have made both functions wrap their code in a launch {} block. To be able to call launch {} like this, you will likely want to make your class implement 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()
    }
    ...
}
READ ALSO
Why does geocoder only return one result?

Why does geocoder only return one result?

I have searched several places, but I always get a single result and not the 5 as I assigned them, why will it?

43
Android App is crashing because of multidex support not enabled?

Android App is crashing because of multidex support not enabled?

my app is crashing when I am trying to user firebase-auth sdk

59
Why OpenCart uses Subquery instead of LEFT JOIN?

Why OpenCart uses Subquery instead of LEFT JOIN?

Recently I was researching opencart source code I found that are using subqueries instead of LEFT JOIN

38
MySQL Duplicate Entry Error on non-primary key

MySQL Duplicate Entry Error on non-primary key

I have a table defined with a single primary/auto-increment key

18