Как получать уведомления, когда одноранговый узел больше не доступен в диапазоне Wi-Fi Direct?
Я разрабатываю приложение для Android, основанное на использовании Wifi Direct API. Я зарегистрировался в своем Activity
a BroadcastReceiver
для того, чтобы получать уведомления о следующих событиях Wifi Direct:
WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION
WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
Я полагал, что любое изменение в списке одноранговых узлов (включение или исключение одного из них в прямой диапазон Wi-Fi) может вызвать BroadcastReceiver
. В моем приложении, когда новый узел найден, его имя правильно включено в ListView
, но если узел покидает диапазон беспроводной связи (или если я выключаю его интерфейс Wi-Fi), то BroadcastReceiver
не вызывается (более конкретно,
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION
Событие не запускается), а имя узла остается в ListView
.
ListView
, но никогда не исключаются. Я уже думал о повторной инициализации канала и WifiP2pManager
экземпляров, но я считаю, что это отключит все пиринги.1 ответ:
Я полагал, что любое изменение в списке одноранговых узлов (включение или исключение одного из них в прямой диапазон Wi-Fi) может привести к запуску BroadcastReceiver.Да, я думаю, что это должно произойти.Мы можем попробовать покопаться в исходном коде и посмотреть, сможем ли мы объяснить это поведение. Примечание: у меня нет решения, которое можно было бы предложить. Но следующее исследование может помочь вам лучше понять "проблему".В моем приложении, когда новый узел найден, его имя правильно включено в ListView, но если узел покидает беспроводной диапазон (или если я отключаю его интерфейс Wi-Fi), BroadcastReceiver не вызывается (более конкретно, WifiP2pManager.Событие WIFI_P2P_PEERS_CHANGED_ACTION не запускается), и имя узла остается в представлении списка.
Начнем отсюда.:
WifiP2pSettings
ссылкаЭтот фрагмент вы видите, когда заходите внастройки > Wifi > Wifi-Direct . Если вы пройдете через код, вы заметите, что реализация очень похожа на проект
WifiDirectDemo
-BroadcastReceiver
прослушивает те же четыре действия (и еще два - одно для обновления пользовательского интерфейса). Причина, по которой мы рассматриваем этот фрагмент, заключается в том, чтобы проверить, является ли сама демонстрация ошибочной. Но, похоже, демо-версия в порядке.Двигаемся дальше-давайте посмотрим, кто транслирует действие
WIFI_P2P_PEERS_CHANGED_ACTION
- в конечном счете, мы заинтересованы в том, чтобы выяснить, почему это не происходит, Как только устройство выходит оффлайн/вне зоны действия. Это приводит нас кWifiP2pService
ссылка .Метод
WifiP2pService # sendPeersChangedBroadcast()
выдает трансляцию:Глядя наprivate void sendPeersChangedBroadcast() { final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); intent.putExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST, new WifiP2pDeviceList(mPeers)); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mContext.sendBroadcastAsUser(intent, UserHandle.ALL); }
WifiP2pService
, можно сказать, чтоsendPeersChangedBroadcast()
вызывается в ответ на несколько событий. Нас интересует вот это:WifiMonitor.P2P_DEVICE_LOST_EVENT
ссылка :.... case WifiMonitor.P2P_DEVICE_LOST_EVENT: device = (WifiP2pDevice) message.obj; // Gets current details for the one removed device = mPeers.remove(device.deviceAddress); if (device != null) { sendPeersChangedBroadcast(); } break; ....
Наконец, кое-что интересное. Посмотрите на
WifiMonitor # handleP2pEvents(String)
отвечает за отправку сообщения, которое попадает в вышеупомянутыйcase
. Поднимитесь по цепочке, чтобы найтиMonitorThread
- статический внутренний класс вWifiMonitor
.MonitorThread # dispatchEvent(String)
вызываетhandleP2pEvents(String)
метод.run()
методMonitorThread
:private static class MonitorThread extends Thread { .... public void run() { //noinspection InfiniteLoopStatement for (;;) { String eventStr = mWifiNative.waitForEvent(); .... } } .... }
Во-первых, мы находимся внутри бесконечного цикла.
Эти два пункта вместе взятые указывают мне, что я не собираюсь получить быстрый ответ из этого-ну, определенно ничего "мгновенного". Метод, которого мы достигли, поднимаясь по цепочке -- во-вторых,
mWifiNative.waitForEvent()
говорит мне, что его , вероятно, блокирующий вызов.MonitorThread # dispatchEvent(String)
- называется изнутри этого бесконечного петля. Давайте проверим, может ли что-то подтвердить нашу обоснованную догадку:Взгляните на
WifiNative
класс связь, особенно на методsetScanInterval(int)
. Этот метод вызывается из классаWifiStateMachine
ссылка . Пройдите через методprocessMessage(Message)
:.... case WifiP2pService.P2P_CONNECTION_CHANGED: NetworkInfo info = (NetworkInfo) message.obj; mP2pConnected.set(info.isConnected()); if (mP2pConnected.get()) { int defaultInterval = mContext.getResources().getInteger( R.integer.config_wifi_scan_interval_p2p_connected); long scanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(), Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS, defaultInterval); // ====>> Interval defined here mWifiNative.setScanInterval((int) scanIntervalMs/1000); } else if (mWifiConfigStore.getConfiguredNetworks().size() == 0) { if (DBG) log("Turn on scanning after p2p disconnected"); sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN, ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs); } ....
Обратите внимание на
defaultInterval
в первомif block
. Это запросR.integer.config_wifi_scan_interval_p2p_connected
, который определяется вconfig.xml
ссылка как:<!-- Integer indicating wpa_supplicant scan interval when p2p is connected in milliseconds --> <integer translatable="false" name="config_wifi_scan_interval_p2p_connected">60000</integer>
60000 МС. Это 1 минута. Таким образом, если
ПосколькуSettings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS
Не задано, то сканирование будет происходить с интервалом в 1 минуту.Находится в глобальных настройках, мы не можем его изменить. На самом деле, его даже нельзя прочесть. Это означает, что единственная гарантия, которую мы имеем здесь, состоит в том, что список сверстников будет обновлен менее чем за минуту. Интервал может, конечно, варьироваться от бренда к бренду.
Чтобы убедиться в этом, я запустил демонстрационную версию на планшетах asus и dell. Как вы уже сказали, появление устройства в Сети было замечено довольно быстро (во время фазы обнаружения). При выключении Wi-Fi, я засекла ответ. Автономное устройство было снято со списка автоматически - с существенной задержкой. Планшет dell взял близко к60 seconds
, чтобы заметить, что asus находится в автономном режиме. Asus же с другой стороны взял45 seconds
.Мне это кажется ограничением, навязанным android. Я не могу сказать почему. Я надеюсь, что кто - то здесь может предложить вам решение-возможно, взять это исследование и исследовать дальше. Но я бы не удивился, если бы решение не существовало (в настоящее время).