2

In Android, I rather frequently need to get results from more than one service that utilizes an asynchronous callback pattern and I want to know if there's a better way to handle this pattern than what I'm doing.

Right now the way I handle it goes something like this: I call both services and pass them my callbacks. In the callback for service A, I check and see if I have a cached result from service B. If I do, then I do whatever I need to do with them. If I don't, I cache the result from service A. I do the same in the callback for service B.

So as an example, I have an activity that displays the user's current location on a map. The map loads asynchronously and calls back to onMapReady. The request for location services calls back to onConnected. In onMapReady, I check to see if I have location services. If I do, I set the location on the map to the user's last location. If I don't, I set the location to a default location and cache the map. In onConnected, I check and see if I have the map. If I do, I set the location on the map to the user's last location. If I don't, I cache the last location.

This pattern works well enough when there are only two services involved, but I can envision scenarios in which I might have three or more, and it seems clumsy. Is there another way I should be handling this?

  • 1
    Sounds like map reduce – candied_orange Dec 9 '16 at 15:20
  • Which language are you using ? Different languages have different approaches for handling callbacks and parallel tasks and continuation. – Machado Mar 9 '17 at 22:27
1

Your asynchronous promise/task/whatever library should have a function to deal with this natively for you. C# has Task.WhenAll, and there's jQuery.when and similar friends in JS. If yours doesn't have this function, find a new one.

0

Disclaimer: I'm not an Android developer.

I would make the callbacks send their results down a queue, and would sit reading from the queue until enough results arrive (with an optional timeout).

Sending results of different types down the same queue is not convenient, though. If possible, (slightly) different result classes may implement a common interface. For wildly disparate results, I could use multiple queues, reading from them sequentially.

If all I care is waiting for all results to arrive, and then proceed, this is enough.

If there's a reasonable sequence when I can start processing of one result somehow, even before the other result arrives, I can order the reads from queues to reflect that:

// Imagine we're trying to help user see if a bus is coming.
// APIs are imaginary throughout.
// We wrap callback-accepting services so that the callbacks
// simply put the result into the queue given.
connection_service.askForConnection(connection_queue);
location_service.askForLocation(location_queue);
// Start using the location, connection may be arriving.
location = location_queue.get();
BusStop the_stop = determineBusStop(location);  // from offline data.
connection = connection_queue.get();
StopInfo info = BusStop.getApproachingBuses(connection);

For your particular case, a geographic map and the position, your approach, the one with cached positions and map tiles, looks most user-friendly: there's always something to show the user, even if it's not the latest.

Too bad your services seem to not to speak in the language of FutureTasks.

-1

Sometimes I use a count, set to the number of items I'm know I'm going to be waiting for. Then make the various calls having delayed callbacks. In each callback I capture what I need from the specific args of that callback, and then call a common routine.

The common routine decrements the count and if the count is non-zero it returns without doing anything further. When the count gets to zero, it runs some code that depends on all the callbacks having completed.

(This could be done using objects or closures.)

Sometimes I use a simple count when I know it and it is locally obvious; other times I dynamically increment the count, such as when I need to wait for a callback to occur, and then that callback may need to issue another call involving another callback, depending on the answers from the former callback.

I'm working with the Chrome API, which loves these delayed callbacks, and begs for a fair amount of machinery around the coordination of various callbacks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.