【问题标题】:How to be notified when a peer is no longer available in the Wi-Fi Direct range?当 Wi-Fi Direct 范围内的对等点不再可用时,如何通知?
【发布时间】:2014-01-12 06:50:14
【问题描述】:

我正在开发一个基于使用 Wifi Direct API 的 Android 应用程序。我已在我的ActivityBroadcastReceiver 中注册,以便收到有关以下 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() 调用,但它没有发现任何“变化”(在这种情况下,对等体的断开连接)。
  • 那我不知道该告诉你什么。没有看到代码,我没有猜测。不过,这似乎应该是一个足够普遍的问题,它已经被考虑在内了。

标签: android android-wifi wifi-direct wifimanager wifip2p


【解决方案1】:

我相信对等点列表中的任何更改(在 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) 方法。

最后,有趣的事情。看MonitorThreadrun()方法:

private static class MonitorThread extends Thread {

    ....

    public void run() {
        //noinspection InfiniteLoopStatement
        for (;;) {
            String eventStr = mWifiNative.waitForEvent();
            ....
        }
    }

    ....
}            
  • 首先,我们处于一个无限循环中。
  • 其次,mWifiNative.waitForEvent() 告诉我它可能是一个阻塞调用。

这两点放在一起向我表明,我不会因此得到迅速的回应——嗯,绝对没有什么“即时”的。我们通过上链到达的方法 - MonitorThread # dispatchEvent(String) - 是从这个无限循环内部调用的。

让我们检查一下是否有什么可以支持我们有根据的猜测:

看看WifiNativeLink,尤其是方法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 强制执行的限制。我说不出为什么。我希望这里有人可以为您提供解决方案 - 可能会进行这项研究并进一步探索。但如果(目前)不存在解决方案,我不会感到惊讶。

【讨论】:

  • 很全面的解释!谢谢
猜你喜欢
  • 1970-01-01
  • 2013-03-09
  • 1970-01-01
  • 2023-01-29
  • 2017-04-24
  • 1970-01-01
  • 2012-11-07
  • 1970-01-01
  • 2021-08-04
相关资源
最近更新 更多