16

我正在开发基于使用Wifi Direct API 的 Android 应用程序。我已在我Activity的 aBroadcastReceiver中注册,以便收到有关以下 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. 在我的应用程序中,当找到一个新的对等点时,它的名称正确包含在 a 中ListView,但是如果对等点离开无线范围(或者如果我关闭了它的 Wi-Fi 接口),BroadcastReceiver则不会调用 (更具体地说,

WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION

事件未触发),并且对等点名称保留在ListView.

我想知道是否有任何方法可以处理这个问题,因为对等名称包含在 中ListView,但从不排除。我已经考虑过重新初始化 Channel 和WifiP2pManager实例,但我相信这会断开所有对等点。

4

1 回答 1

30

我相信对等点列表中的任何更改(在 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- 中的静态内部类WifiMonitorMonitorThread # 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_connectedconfig.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 强制执行的限制。我说不出为什么。我希望这里有人可以为您提供解决方案 - 可能会进行这项研究并进一步探索。但是,如果(目前)不存在解决方案,我不会感到惊讶。

于 2014-08-06T06:55:04.750 回答