How to isolate asynchronous requests

156 Views Asked by At

I am stuck on a problem, deriving from the following facts:

  • Android Main thread should not be blocked
  • I need to perform dependent network calls (for example a login request onSuccess of an authentication request)
  • onSuccess of the login request I need to update the UI (like navigating from an Activity to another).

I could solve this issue this just by nesting the code in Volley directly in my Activity and having this pattern:

authenticationRequest() {
     onSuccess(): loginRequest() {
           onSuccess(): navigateTo(someActivity)
           onError(): // display some error
     }
     onError(): // display some error
}

And this could also be an exceptional case since it occurs just once in the application. However, you can guess that there may be some other cases of request B getting triggered on response of A, but I could be interested in using only A and not B in some other scenarios.

That's the reason why I think it would be great to isolate methods independently and let me compose them only when necessary.

The problem is that the asynchronous nature of these functions doesn't let me avoid the dependency. Instead, it seems like dependency implies synchronous requests or duplicated nested code everywhere. I am never able to have in my Activity something like:

authenticationRequest()
// wait for the result without freezing main thread
loginRequest() 
// wait for the result without freezing main thread
navigateTo(someActivity)

The closest solution I was getting was a little verbose and a little dirty: create observable live data and do postValue(response) where response is the value onSuccess or onError; consequently, in the Activity I had something like:

authenticationRequest()
authenticationResponse.observe(this, {
       loginRequest()
       loginResponse.observe(this, {
             navigateTo(someActivity)
       })
})

but this solution overcomplicates the management of observable data getting triggered twice when I go back and forward in some Activities.

Do you have any better suggestion?

Edit Note: the order of the functions execution matters.

1

There are 1 best solutions below

2
broot On

Your question is pretty unfocused. After reading both your question and comments you seem to have several concerns regarding synchronous/asynchronous execution. I won't answer all your concerns, but I can at least give you some insights on this topic.

  1. In ideal world, the only reason to choose between synchronous and asynchronous is what we (the caller) currently need. If we need to execute A, B and C requests, where B uses data from A and C uses data from B, then we invoke them sequentially. If they are independent, we invoke them concurrently and join on them all.
  2. Synchronous code is easier to develop and maintain and therefore it is generally preferable over async if we don't need parallel execution.
  3. Historically, we were forced to use async code for strictly technical reasons. Such code have better performance and does not block critical threads like UI thread.
  4. Because of 3. we often use async code. Still, we don't like it because of 2. We invented tools that help us work with async code in a more convenient way, for example futures/premises. They're far from ideal, but often they're better than callbacks.
  5. Recently, we invented tools that have advantages of both synchronous and asynchronous code, placing us much closer to the ideal situation described in 1. These tools for JVM are mostly: Kotlin coroutines and Project Loom (not yet available), but there are also others, e.g.: Quasar. With coroutines and when keeping all long-running functions suspendable, we can code like this: val a = requestA(); val b = requestB(a); requestC(b); or: launch { requestA() }; launch { requestB() }; launch { requestC() } - whichever we need at the time. The performance is always as we code asynchronously.