detecting disconnection from a WiFi access point
Asked Answered
A

2

10

I am trying to use a BroadcastReceiver to detect when the phone has disconnected from a WiFi access point. To do this, I registered my BroadcastReceiver in the manifest:

<receiver android:name="com.eshayne.android.WiFiBroadcastReceiver">
    <intent-filter>
        <action android:name="android.net.wifi.STATE_CHANGE" />
    </intent-filter>
</receiver>

In my WiFiBroadcastReceiver class, I am checking for a NETWORK_STATE_CHANGED_ACTION action and looking at the NetworkInfo's detailed state:

if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
    NetworkInfo info = (NetworkInfo)intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
    android.util.Log.d("com.eshayne.android.WiFiBroadcastReceiver", "network state change - detailedState=" + info.getDetailedState() + ": " + info.toString());
    if (info.getDetailedState() == DetailedState.DISCONNECTED) {
        ...
    }
    else if (info.getDetailedState() == DetailedState.CONNECTED) {
        ...
    }

The problem I'm seeing is that when the phone leaves the WiFi access point's range, my "disconnected" callback gets called 6 times - pretty regularly at about once every 15 seconds - before it stops. So far I haven't been able to find any distinguishing characteristics between each callback's NetworkInfo. Each NetworkInfo object being written to the log looks like this:

02-18 10:16:51.918 D/com.eshayne.android.WiFiBroadcastReceiver( 1511): network state change - detailedState=DISCONNECTED: NetworkInfo: type: WIFI[], state: DISCONNECTED/DISCONNECTED, reason: (unspecified), extra: (none), roaming: false, failover: false, isAvailable: true

It's also not an issue of the phone wandering in and out of WiFi range, as my "connected" callback is not called in between "disconnected" callbacks. Nor are any other states being triggered in between. Just a rapid series of 6 callbacks each with a detailedState of DISCONNECTED.

Is there a better way for me to detect when the phone has lost its WiFi connection, so that my callback only gets called once per disconnect? Or any way to detect which of the 6 callbacks I'm seeing is the "final" one?

Asch answered 18/2, 2011 at 16:44 Comment(2)
What exactly is the issue here? When you say the phone is not reconnecting after the 1st broadcast, isn't any of the 6 as good as the other?Ogbomosho
The issue is that I don't want my broadcast receiver to perform the same disconnect-handling logic six times.Asch
S
2

You say it's a "rapid series of 6 disconnected callbacks", but your if/else-if only checks for DISCONNECTED and CONNECTED, with what looks like no default block to handle all other cases. From the NetworkInfo.DetailedState api page, there's 10 possible states that could be returned by NetworkInfo.getDetailedState(), including "connecting", "scanning", "disconnecting", all of which would be plausible behavior for a phone that just got disconnected from a network.

Throw down a default case that alerts you to any change in wifi state, not just "CONNECTED" and "DISCONNECTED". You might find that the phone is rotating between several different states, and not just shotgunning the same one at you six times. Hopefully from there, how to proceed in your code will be a little clearer.

Siler answered 18/2, 2011 at 21:8 Comment(1)
Thank you. I should have clarified - I am actually logging each entire NetworkInfo, before I check for CONNECTED or DISCONNECTED. They're all DISCONNECTED. I've updated my original post to show what all the log entries look like. If you can think of anything else to check on each callback to try to distinguish them, I'll give that a try.Asch
U
0

One workaround you could use is to maintain your last callback action somewhere (global state, shared preferences, etc.) and only run your callbacks if the action has changed.

enum NetworkCallbackAction { None, Disconnected, Connected };
NetworkCallbackAction lastHandledAction = NetworkCallbackAction.None;

// ...

if (info.getDetailedState() == DetailedState.DISCONNECTED) {
  if (lastHandledAction != NetworkCallbackAction.Disconnected) {
    lastHandledAction = NetworkCallbackAction.Disconnected;
    // ...
  }
}
else if (info.getDetailedState() == DetailedState.CONNECTED) {
  if (lastHandledAction != NetworkCallbackAction.Connected) {
    lastHandledAction = NetworkCallbackAction.Connected;
    // ...
  }
}

A nicer abstraction of this logic would be to write a broadcast receiver who's only job is to normalize the network state changes into consistent events and smooth out the real-world quirks, and then re-broadcast its own actions. This allows you to simplify the raw updates into something that makes sense for your application. It could, for example, remember it's last broadcasts and only broadcast changes (similar to what the code above does). In case of bursts of network change intents it could wait a few seconds before broadcasting the last state it received.

Unlade answered 20/2, 2012 at 21:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.