我相信对等点列表中的任何更改(在 Wifi Direct 范围内包含或排除对等点)都可能触发广播接收器。
是的,我认为这应该发生。
在我的应用程序中,当找到新的对等点时,它的名称会正确包含在 ListView 中,但如果对等点离开无线范围(或者如果我关闭其 Wi-Fi 接口),则不会调用 BroadcastReceiver (更具体地说,未触发 WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION 事件),并且对等点名称保留在 ListView 中。
我们可以尝试挖掘源代码,看看是否可以解释这种行为。
注意:我没有提供解决方案。但是,以下研究可能会帮助您更好地理解“问题”。
我们从这里开始:WifiP2pSettingsLink
这是您进入 设置 > Wifi > Wifi-Direct 时看到的片段。如果您仔细阅读代码,您会注意到实现与WifiDirectDemo 项目非常相似——BroadcastReceiver 侦听相同的四个操作(另外两个 - 一个用于 UI 更新)。我们查看这个片段的原因是检查演示本身是否存在缺陷。但是,看起来演示还不错。
继续前进 - 让我们看看谁在广播动作 WIFI_P2P_PEERS_CHANGED_ACTION - 最终,我们有兴趣找出为什么在设备离线/超出范围时不会立即发生这种情况。这会将我们带到WifiP2pServiceLink。
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_EVENTLink:
....
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)。这个方法是从类WifiStateMachineLink调用的。通过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 强制执行的限制。我说不出为什么。我希望这里有人可以为您提供解决方案 - 可能会进行这项研究并进一步探索。但如果(目前)不存在解决方案,我不会感到惊讶。