我相信对等点列表中的任何更改(在 Wifi Direct 范围内包含或排除对等点)都可能触发广播接收器。
是的,我认为这应该发生。
在我的应用程序中,当找到一个新的对等点时,它的名称会正确包含在 ListView 中,但是如果对等点离开无线范围(或者如果我关闭其 Wi-Fi 接口),则不会调用 BroadcastReceiver(更具体地说, WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION 事件未触发),并且对等点名称保留在 ListView 中。
我们可以尝试挖掘源代码,看看是否可以解释这种行为。
注意:我没有提供解决方案。但是,以下研究可能会帮助您更好地理解“问题”。
我们将从这里开始:WifiP2pSettings
链接
这是您转到Settings > 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
链接:
....
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)
——在这个无限循环中被调用。
让我们检查一下是否有东西可以支持我们有根据的猜测:
看一下LinkWifiNative
类,尤其是方法。从类Link调用此方法。通过方法: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
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 强制执行的限制。我说不出为什么。我希望这里有人可以为您提供解决方案 - 可能会进行这项研究并进一步探索。但是,如果(目前)不存在解决方案,我不会感到惊讶。