обнаружение отключения от точки доступа 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) {
        ...
    }

Проблема, которую я вижу, заключается в том, что когда телефон покидает зону действия точки доступа Wi-Fi, мой «отключенный» обратный вызов вызывается 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

Это также не проблема того, что телефон блуждает в зоне действия Wi-Fi и выходит за ее пределы, поскольку мой «подключенный» обратный вызов не вызывается между «отключенными» обратными вызовами. Никакие другие состояния не запускаются между ними. Просто быстрая серия из 6 обратных вызовов, каждый из которых имеет подробное состояние DISCONNECTED.

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


person eshayne    schedule 18.02.2011    source источник
comment
В чем именно здесь проблема? Когда вы говорите, что телефон не подключается после 1-й трансляции, разве ни один из 6 не так хорош, как другой?   -  person Heiko Rupp    schedule 18.02.2011
comment
Проблема в том, что я не хочу, чтобы мой широковещательный приемник выполнял одну и ту же логику обработки разъединения шесть раз.   -  person eshayne    schedule 18.02.2011


Ответы (2)


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

Создайте случай по умолчанию, который предупреждает вас о любом изменении состояния Wi-Fi, а не только о «ПОДКЛЮЧЕНО» и «ОТКЛЮЧЕНО». Вы можете обнаружить, что телефон переключается между несколькими разными состояниями, а не просто стреляет в вас шесть раз одним и тем же. Надеемся, что после этого, как действовать в вашем коде, станет немного понятнее.

person Alexander Lucas    schedule 18.02.2011
comment
Спасибо. Я должен был уточнить - я фактически регистрирую каждую всю NetworkInfo, прежде чем проверять ПОДКЛЮЧЕНО или ОТКЛЮЧЕНО. Они все ОТКЛЮЧЕНЫ. Я обновил свой исходный пост, чтобы показать, как выглядят все записи журнала. Если вы можете придумать что-нибудь еще, чтобы проверить каждый обратный вызов, чтобы попытаться отличить их, я попробую. - person eshayne; 19.02.2011

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

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

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

person orip    schedule 20.02.2012