当 Wi-Fi Direct 范围内的对等点不再可用时,如何通知?
Posted
技术标签:
【中文标题】当 Wi-Fi Direct 范围内的对等点不再可用时,如何通知?【英文标题】:How to be notified when a peer is no longer available in the Wi-Fi Direct range? 【发布时间】:2014-01-12 06:50:14 【问题描述】:我正在开发一个基于使用 Wifi Direct API 的 android 应用程序。我已在我的Activity
和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
我相信对等点列表中的任何更改(在 Wifi Direct 范围内包含或排除对等点)都可能触发BroadcastReceiver
。在我的应用程序中,当找到新的对等点时,它的名称正确包含在 ListView
中,但如果对等点离开无线范围(或者如果我关闭其 Wi-Fi 接口),则不会调用 BroadcastReceiver
(更具体地说,
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION
事件未触发),对等点名称仍保留在ListView
中。
我想知道是否有任何方法可以处理这个问题,因为对等名称包含在ListView
中,但从未排除。我已经考虑过重新初始化 Channel 和 WifiP2pManager
实例,但我相信这会断开所有对等点。
【问题讨论】:
除非您最近听说过(或来自)他们,否则称其为“陈旧的”。定期删除过时的名称。 cHao,我认为我不能简单地删除它们,因为当检测到WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION
时,会完成“对等列表”更新(系统在discoverPeers(channel, actionListener)
方法之后异步调用此事件称呼)。另一个问题是:这个“垃圾收集器”应该运行多长时间?
我认为库本身会丢弃它再也看不到的对等点(尽管它可能不会为它们发出事件)。你是仅仅依靠变更事件来告诉你发生了什么,还是偶尔requestPeers()
?
我尝试了这两种方法,但都没有成功......我还使用了Handler
来执行定期的requestPeers()
调用,但它没有发现任何“变化”(在这种情况下,对等体的断开连接)。
那我不知道该告诉你什么。没有看到代码,我没有猜测。不过,这似乎应该是一个足够普遍的问题,它已经被考虑在内了。
【参考方案1】:
我相信对等点列表中的任何更改(在 Wifi Direct 范围内包含或排除对等点)都可能触发广播接收器。
是的,我认为这应该发生。
在我的应用程序中,当找到新的对等点时,它的名称会正确包含在 ListView 中,但如果对等点离开无线范围(或者如果我关闭其 Wi-Fi 接口),则不会调用 BroadcastReceiver (更具体地说,未触发 WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION 事件),并且对等点名称保留在 ListView 中。
我们可以尝试挖掘源代码,看看是否可以解释这种行为。
注意:我没有提供解决方案。但是,以下研究可能会帮助您更好地理解“问题”。
我们从这里开始:WifiP2pSettings
Link
这是您进入 设置 > Wifi > Wifi-Direct 时看到的片段。如果您仔细阅读代码,您会注意到实现与WifiDirectDemo
项目非常相似——BroadcastReceiver
侦听相同的四个操作(另外两个 - 一个用于 UI 更新)。我们查看这个片段的原因是检查演示本身是否存在缺陷。但是,看起来演示还不错。
继续前进 - 让我们看看谁在广播动作 WIFI_P2P_PEERS_CHANGED_ACTION
- 最终,我们有兴趣找出为什么在设备离线/超出范围时不会立即发生这种情况。这会将我们带到WifiP2pService
Link。
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
Link:
....
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)
方法。
最后,有趣的事情。看MonitorThread
的run()
方法:
private static class MonitorThread extends Thread
....
public void run()
//noinspection InfiniteLoopStatement
for (;;)
String eventStr = mWifiNative.waitForEvent();
....
....
首先,我们处于一个无限循环中。
其次,mWifiNative.waitForEvent()
告诉我它可能是一个阻塞调用。
这两点放在一起向我表明,我不会因此得到迅速的回应——嗯,绝对没有什么“即时”的。我们通过上链到达的方法 - MonitorThread # dispatchEvent(String)
- 是从这个无限循环内部调用的。
让我们检查一下是否有什么可以支持我们有根据的猜测:
看看WifiNative
类Link,尤其是方法setScanInterval(int)
。这个方法是从类WifiStateMachine
Link调用的。通过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);
....
注意第一个if block
中的defaultInterval
。它正在请求R.integer.config_wifi_scan_interval_p2p_connected
,它在config.xml
Link 中定义为:
<!-- 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 分钟。
由于WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS
被置于全局设置下,我们无法更改它。事实上,它甚至无法读取。意思是,我们这里唯一的保证是节点列表将在一分钟内刷新。间隔当然可以因品牌而异。
为了验证这一点,我在华硕平板电脑和戴尔平板电脑上运行了演示。就像你说的,设备上线很快就被注意到了(在发现阶段)。在关闭 wifi 时,我记录了响应。离线设备已自动从列表中删除 - 有相当长的延迟。戴尔平板电脑接近60 seconds
注意到华硕处于离线状态。另一方面,华硕拿走了45 seconds
。
对我来说,这似乎是 android 强制执行的限制。我说不出为什么。我希望这里有人可以为您提供解决方案 - 可能会进行这项研究并进一步探索。但如果(目前)不存在解决方案,我不会感到惊讶。
【讨论】:
很全面的解释!谢谢以上是关于当 Wi-Fi Direct 范围内的对等点不再可用时,如何通知?的主要内容,如果未能解决你的问题,请参考以下文章