Search code examples
kotlinrx-javarx-kotlin

How to add andthen() operator under condition or inside a loop Rx Kotlin


I'm trying to chain some rx operations under a condition but the andthen() inside the apply does not execute. Is this correct? operation returns a Completable. Android studio gives me the warning "The result of andThen is not used" in both andthen() calls.

operation.apply {
   if (true) {
      andthen(thisDoesNotExecute())
   }
}
.andThen(thisExecutes())

Same happens here, only doAnOperation(aList[0]) is executed, should I add a .subscribe inside the andThen()?

operation(aList[0])
    .apply {
        if (aList.size > 1) {
            for (item in aList.sublist(1, aList.size)) {
                andThen(operation(item))
            }
        }
    }
    .subscribe()

Solution

  • andThen returns a new instance with your transformation, it doesn't mutate the original source, so you have to use its return value if you want to take it into account.

    apply() returns the instance on which you call it, so in your case it will return the initial operation, not the result of the andThen() transformation.

    You should read up on scope functions to understand which one suits you best. Here you want to return the result of andThen(), so you need a scope function that returns the lambda result, not the receiver. Then you can choose whether you want to have the operation object as this or it inside the lambda, which decides between run or let.

    Let's go with let here:

    operation.let {
        if (condition) {
            it.andthen(thisDoesNotExecute())
        } else {
            it
        }
    }
    .andThen(thisExecutes())
    

    If you need this often, you could create your own extension function to encapsulate that.

    You could also use an intermediate variable instead of course:

    val intermediate = if (condition) {
        operation.andThen(thisDoesNotExecute())
    } else {
        operation
    }
    val result = intermediate.andThen(thisExecutes())
    

    For your loop, you could use fold() like this:

    aList.fold(Completable.complete()) { acc, item -> acc.andThen(operation(item)) }
         .subscribe()
    

    Or to stay really close to your initial approach without initial complete() element, you could map first and then use reduce():

    aList.map { operation(it) }
         .reduce { c1, c2 -> c1.andThen(c2) }
         .subscribe()