【问题标题】:Unable to both start and discover a specific service with Wifi Direct无法使用 Wifi Direct 启动和发现特定服务
【发布时间】:2013-08-19 09:59:42
【问题描述】:

我对 Android 编程很陌生。但是我已经为此工作了一个多星期了,它开始变得很糟糕。

我的想法是我想使用 Wifi Direct 连接两个设备。但我只想连接到那些正在运行我的应用程序的人。此外,我希望用户能够看到其他设备的一些信息(例如用户名),而不仅仅是 WifiP2pDevice 中包含的 MAC 或 Android_XXXX 名称。这就是为什么我决定寻找其他设备的设备应该同时启动应用程序服务并搜索也在广播该服务的对等点。

问题(我正在使用两台真实设备进行测试)是,即使它们运行完全相同的代码,但其中只有一个正在获取服务发现回调(下面的 onDnsSd... 侦听器)。因此,一方以正确的方式行事,而另一方则不然。此外,我正在获得“旧”服务,这意味着显然每次我启动服务时(即使我取消了以前启动的服务),该服务似乎仍然在至少几分钟内广播。

我包含了我的代码的缩短版本:

public class MoveFlufietsDialogFragment extends DialogFragment implements ChannelListener, DeviceActionListener {

    public final HashMap<String, FlufietsPeer> mBuddies = new HashMap<String, FlufietsPeer>();

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
    ...
        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);

        mManager = (WifiP2pManager) getActivity().getSystemService(Context.WIFI_P2P_SERVICE);
        mChannel = mManager.initialize(getActivity(), getActivity().getMainLooper(), null);
        ...
        startRegistration();
        discoverFlufietsService();
        ...
    }


    public void discoverFlufietsService() {
        DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
            @Override
            public void onDnsSdTxtRecordAvailable(String fullDomain, Map record, WifiP2pDevice device) {
                // This and the next listener are only called in one of the devices.
                String serviceName = (String) record.get("serviceName");
                if ((serviceName != null) && (serviceName.equals("flufiets")) {
                    // I put the record data in the mBuddies HashMap.
                    ...
                    mBuddies.put(device.deviceAddress, myPeerDataStructure);
                }
            }
        };

        DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
            @Override
            public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice resourceType) {
                if (mBuddies.containsKey(resourceType.deviceAddress)) {
                    FlufietsPeer flufietsPeer = mBuddies.get(resourceType.deviceAddress);
                    WiFiPeerListAdapter adapter = ((WiFiPeerListAdapter) mFragmentList.getListAdapter());
                    adapter.add(flufietsPeer);
                    adapter.notifyDataSetChanged();
                }
            }
        };

        mManager.setDnsSdResponseListeners(mChannel, servListener, txtListener);

        WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
        mManager.addServiceRequest(mChannel, serviceRequest, new ActionListener() {
            // onSuccess/onFailure toasts.
        });

        mManager.discoverServices(mChannel, new WifiP2pManager.ActionListener() {
            // onSuccess/onFailure toasts.
        });
    }

    public void startRegistration() {
        mManager.clearLocalServices(mChannel, new ActionListener() {
            // onSuccess/onFailure toasts.
        });

        Map record = new HashMap();
        record.put("serviceName", "flufiets");
        ...

        WifiP2pDnsSdServiceInfo serviceInfo = WifiP2pDnsSdServiceInfo.newInstance(flufietsService, "_tcp", record);

        mManager.addLocalService(mChannel, serviceInfo, new ActionListener() {
            // onSuccess/onFailure toasts.
        });
    }

    @Override
    public void onResume() {
        super.onResume();
        mReceiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);
        getActivity().registerReceiver(mReceiver, mIntentFilter);
    }

    @Override
    public void onPause() {
        super.onPause();
        getActivity().unregisterReceiver(mReceiver);
    }

    @Override
    public void onStop() {
        super.onStop();
        mManager.clearLocalServices(mChannel, new ActionListener() {
            // onSuccess/onFailure toasts.
        });
    }

    ...
}

问题似乎与设备本身无关(有时有效,有时无效,但总是仅在其中一个方面)。我怀疑这与尝试发现我们自己正在广播的服务有关,或者与两个设备提供相同的服务有关。我曾尝试更改服务的名称,因此每个设备都会提供“发送”或“接收”服务,但它不起作用。我只在其中一个设备中获得调用 (onDnsSd...) 的回调。

关于获取旧服务的事情,当我总是清除它们时,这很奇怪(我确实在服务记录数据中包含了一个时间戳,我总是可以丢弃除最后一个之外的所有内容,但似乎不合逻辑) .

有什么想法吗?任何帮助将不胜感激,因为编写应用程序不再有趣 (:-)=

非常感谢!

【问题讨论】:

  • 这里之前有人试过吗?拜托,我仍然想知道我可能做错了什么......
  • 您好,我还可以确认 WiFi Direct 的 Android 实现有时会出现不一致的行为。我还有一个连接到“自身”的应用程序,并注意到一个或两个实例可以停止检测每个实例的存在。我认为这是因为内核内部的伪优化过于复杂(包括remembered groups 的缓存,似乎偶尔受到干扰)。似乎有帮助的是:关闭 WiFi 设置中的WiFi optimization 复选框并大量调用discoverPeers/stopPeerDiscovery,例如通过适合更好的用户体验的超时(约 5 秒)。
  • 你有没有让它工作?我遇到了同样的情况,结果非常随机,只有一部分得到回调。

标签: android android-service android-wifi wifi-direct


【解决方案1】:

您需要等到 clearLocalService 调用成功后再添加本地服务。所以把 addLocalService 调用放到 clearLocalServices 的 onSuccess 回调中。

【讨论】:

猜你喜欢
  • 2013-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多