Search code examples
androidbroadcastreceiverandroid-wifiintentservice

How to make an IntentService wait until BroadcastReceiver has finished executing?


I've got an IntentService which should perform some tasks after WiFi has been turned on.

I'm using a BroadcastReceiver on WifiManager.WIFI_STATE_CHANGED_ACTION to listen for WiFi changes.

The problem:

When I turn on WiFi via wifiManager.setWifiEnabled(true) the BroadcastReceiver only receives the states WifiManager.WIFI_STATE_DISABLED and WifiManager.WIFI_STATE_ENABLING. Then the IntentService is destroyed before the actual WifiManager.WIFI_STATE_ENABLED state can be received.

If I put Thread.sleep(2000) at the end of onHandleIntent() it works, but there must be a better solution?

Questions:

  1. Why is the state WifiManager.WIFI_STATE_DISABLED broadcasted at all when I'm calling wifiManager.setWifiEnabled(true)?
  2. How can I make the onHandleIntent() method wait until the state WifiManager.WIFI_STATE_ENABLED has been retrieved?

Code:

public class BackupService extends IntentService {

    private BroadcastReceiver mWifiStateChangedReceiver;

    public BackupService() {
        super("BackupService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        final WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
        mWifiStateChangedReceiver = new BroadcastReceiver() {

            @Override
            public void onReceive(Context context, Intent intent) {
                int wifiState = intent.getIntExtra(
                        WifiManager.EXTRA_WIFI_STATE,
                        WifiManager.WIFI_STATE_UNKNOWN);
                if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
                    // PERFORM TASK...
                }
            }
        };
        registerReceiver(mWifiStateChangedReceiver, new IntentFilter(
                WifiManager.WIFI_STATE_CHANGED_ACTION));
        wifiManager.setWifiEnabled(true);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mWifiStateChangedReceiver != null) {
            unregisterReceiver(mWifiStateChangedReceiver);
        }
    }
}

Solution

  • How can I make the onHandleIntent() method wait until the state WifiManager.WIFI_STATE_ENABLED has been retrieved?

    Ideally, you don't, as WiFi may not be available, and so you may never receive such a broadcast.

    Instead:

    • Move your BroadcastReceiver to be one registered in the manifest, initially disabled
    • If the IntentService determines that it needs to wait for WiFi, have it enable the existing BroadcastReceiver via PackageManager and setComponentEnabledSetting(), then return out of onHandleIntent()
    • The BroadcastReceiver would use startService() to send a command to be processed by your IntentService once WiFi is ready, at which point it can then disable itself via PackageManager and setComponentEnabledSetting()