Обнаружение отключения от точки доступа WiFi

Я пытаюсь использовать BroadcastReceiver для обнаружения, когда телефон отключился от точки доступа WiFi. Для этого я зарегистрировал свой BroadcastReceiver в манифесте:

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

В моем классе WiFiBroadcastReceiver я проверяю действие NETWORK_STATE_CHANGED_ACTION и просматриваю подробное состояние NetworkInfo:

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) {
        ...
    }

Проблема, которую я вижу, заключается в том, что когда телефон покидает диапазон точек доступа WiFi, мой "отключенный" обратный вызов вызывается 6 раз - довольно регулярно примерно раз в 15 секунд - до его остановки. До сих пор мне не удалось найти каких-либо отличительных характеристик между каждым обратным вызовом NetworkInfo. Каждый объект NetworkInfo, записываемый в журнал, выглядит следующим образом:

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

Это также не проблема телефона, блуждающего по и из диапазона WiFi, поскольку мой "подключенный" обратный вызов не вызывается между "отключенными" обратными вызовами. Кроме того, между ними не возникают другие состояния. Просто быстрая серия из 6 обратных вызовов, каждая из которых содержит подробное состояние DISCONNECTED.

Есть ли лучший способ обнаружить, когда телефон потерял свое WiFi-соединение, так что мой callback получает только один раз для отключения? Или любой способ определить, какой из 6 обратных вызовов я вижу, является "окончательным"?

Ответ 1

Вы говорите, что это "быстрая серия из 6 отключенных обратных вызовов", но ваш if/else - если только проверяет DISCONNECTED и CONNECTED, то, что похоже на блокировку по умолчанию для обработки всех других случаев. На странице apa NetworkInfo.DetailedState существует 10 возможных состояний, которые могут быть возвращены NetworkInfo.getDetailedState(), включая "соединение", "сканирование", "отключение", и все это было бы правдоподобным поведением для телефона, который только что отключился от сети.

Отбросьте случай по умолчанию, который предупреждает вас о любых изменениях в состоянии wifi, а не только "CONNECTED" и "DISCONNECTED". Вы можете обнаружить, что телефон вращается между несколькими различными состояниями, а не только выстрелил один и тот же один у вас шесть раз. Надеюсь, оттуда, как действовать в вашем коде будет немного понятнее.

Ответ 2

Один способ обхода, который вы можете использовать, - это поддерживать ваше последнее действие обратного вызова где-нибудь (глобальное состояние, общие настройки и т.д.) и только выполнять свои обратные вызовы, если действие изменилось.

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;
    // ...
  }
}

Лучше абстракция этой логики заключалась бы в написании широковещательного приемника, который только задание должно нормализовать изменения состояния сети в согласованные события и сгладить реальные черты реального мира, а затем повторно транслировать свои собственные действия. Это позволяет упростить необработанные обновления во что-то, что имеет смысл для вашего приложения. Например, он мог запомнить последние передачи и только трансляцию изменений (аналогично тому, что делает код выше). В случае всплесков сетевых изменений он может подождать несколько секунд, прежде чем передавать последнее полученное состояние.