Search code examples
androiddesign-patternsandroid-intentscreenwifi

Android: Design Pattern for asynchronous events (intents) handling


I'm developing an app which interacts with phone's WiFi, Bluetooth, Mobile Network. The app is mainly a Service, and the GUI doesn't play a central role.

The core of the app, and the principal method of the service class is a single method which receives all intents that the app needs to receive:

public void handleIntent(Intent intent){

It then extracts the intent's action and calls a specific handler method for the corresponding intent's action, for instance when receiving a SCREEN_ON, it would call

private void handleScreenOn(){

Problem is that some tasks on the phone take some time, so that some other events may occur in the middle of the processing of the task, that should change processing.

For instance, turning ON the Wifi would take a couple of seconds, sending several intents WIFI_STATE_CHANGED_ACTION before it's actually completed. In the middle of the WiFi being enabled, the user can turn off the screen so that a SCREEN_OFF intent would be received.

Now say that my app's goal is to turn off WiFi when screen gets turned Off. There is a situation where a problem occurs:

  1. Initial situation: Screen is On, WiFi is Off
  2. User toggles WiFi setting to enable it. Wifi starts getting enabled
  3. User almost immediately turns screen Off
  4. The app receives the SCREEN_OFF intent but since WiFi is not enabled yet, then it believes that there is no need to disable it
  5. Wifi enabling gets finished, and Wifi stays enabled despite the screen being off.

How to solve it?

Currently, in step 5, when Wifi gets finally enabled, I would test whether screen is off or not to turn off wifi again. This solution requires many if / else handling all possible cases.

I'm sure there must be some cleaner way of doing it, handling a stack of intents, or something like this...

Anyone with some good design patter or good advice on how to do it cleanly?


Solution

  • Consider sending an "action completed" event whenever you (asynchronously) complete the reaction to some event. Now you can add some logic in handleIntent() to achieve a consistent state. The logic is at a central position in your components and code duplication is avoided.

    Alternatively you can try to serialize your events: i.e. when an event occurs which may invalidate the outcome of some not yet finished action (you need to manage a list of not completed action, completion can be detected as outlined above) postpone its handling until all those actions are completed. To decide which events may depend on other events a simple, static lookup-table should suffice.