【问题标题】:Bluetooth RFCOMM connection couldn't be established consecutively on Android 4.2Android 4.2 无法连续建立蓝牙 RFCOMM 连接
【发布时间】:2012-11-19 19:17:38
【问题描述】:

我有一个应用程序通过蓝牙通过 RFCOMM 与自定义设备通信。通信代码基于BluetoothTalk示例工程。它之前在 Galaxy S3、Galaxy S2、Galaxy Note 和 Nexus 7 上都可以正常运行。

最近 Nexus 7 升级到 Android 4.2 之后,出现如下问题:

  1. 当你第一次使用app建立连接时,即设备刚开机,app刚启动,没问题,可以正常获取数据。

    李>
  2. 然后,如果您停止通信,并尝试重新启动,通信将失败并出现错误“java.io.IOException: bt socket closed, read return: -1”。从那时起,无论您尝试重新连接多少次,它总是失败。

  3. 让它再次工作的唯一方法是,如果你重新启动自定义设备和应用程序,然后尝试连接,通信就会正常。但是,一旦您停止并重新启动通信,它就会继续失败。

我借了一台装有 Android 4.2 的 Nexus 4,但问题仍然存在。

这真的很烦人,因为我们设备的主要价值在于依赖蓝牙 RFCOMM 应用程序。我仔细检查了 Android 4.2 中关于 BT 的文档,没有发现任何重大变化。我对自己的代码相当有信心,因为它适用于任何不运行 4.2 的 Android 设备

任何提示或建议将不胜感激。该设备需要在 12 月初进行演示,我们非常希望尽快解决这个问题。

编辑:现在 4.2.1 已经发布,但问题仍未解决。我们至少可以确认它是否正在工作并且很快就会修复吗?

【问题讨论】:

    标签: android bluetooth rfcomm


    【解决方案1】:

    这对您帮助不大,但请注意,Google 在 4.2 中引入了全新的蓝牙堆栈。

    这应该是一件好事 - 以我作为用户和开发人员的经验,带有 Bluez(旧组合)的 Android 从来没有可靠地运行,所以我很高兴听到他们进行了彻底的重写。

    我想我只能说您在新堆栈中遇到了错误或怪癖。很遗憾听到新堆栈也存在问题。

    关于您的演示,请注意 Google 会发布其所有 Nexus 设备 (https://developers.google.com/android/nexus/images) 的固件映像,并且将它们刷写到您的设备相当容易。

    所以我建议你提交一个错误报告,然后将你的设备刷到 4.1.2。

    【讨论】:

    • 有兴趣知道。但如果是这种情况,他们应该公开承认并给出估计的错误修复日期。此时我更想知道这是否确实是他们的错误,或者有什么快速的技巧可以解决这个问题
    • 另一方面,有些应用程序似乎与 4.2.1 和 BT 连接一起工作 - 所以我的一个应用程序用户告诉我,他有 4.2.1(我的应用程序因错误而崩溃上面太可惜了,还是没找到“窍门”)
    • 这些应用程序是否使用 SPP 配置文件?我试过4.2.2,好像问题还没有解决
    【解决方案2】:

    在我的测试中也发生过这种情况。我是 BluetoothChat 示例代码,您应该查看 connectionLost 方法。我不记得是否有任何变量可以保持丢失的连接数,但您可以自己添加。在 connectionLost 方法中,测试丢失的连接数是否小于预定义的数量(在我的情况下为 3)。如果是这样,请使用 mHandler(吐司)向 UI 发送一条消息,然后再次调用 connect(device)。如果不是这样(您失去连接超过 3 次),请调用 stop() 方法。

    还要确保像这样在 ConnectThread 中打开套接字:

        public ConnectThread(BluetoothDevice device, boolean isSecure) {
            mmDevice = device;
            BluetoothSocket tmp = null;
            mSocketType = isSecure ? "Secure" : "Insecure";
            // Get a BluetoothSocket for a connection with the given BluetoothDevice
            if (isSecure) {
                // reflection is better to use
                Method m = null;
                try {
                    Log.d(TAG, "create reflection");
                    m = device.getClass().getMethod("createRfcommSocket",new Class[] { int.class });
                    } catch (NoSuchMethodException e1) {
                    e1.printStackTrace();
                }
                try {
                    tmp = (BluetoothSocket) m.invoke(device, 1);
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
                mmSocketFallBack = tmp;
            } else {
                Log.d(TAG, "create insecure");
                try {
                    tmp = device
                            .createInsecureRfcommSocketToServiceRecord(MY_UUID);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            mmSocket = mmSocketFallBack;
        }
    

    您的 connectionLost 应该类似于:

    public void connectionLost() {
        init = false;
        Log.d(TAG, "connectionLost -> " + mConnectionLostCount);
        mConnectionLostCount++;
      if (mConnectionLostCount < 3) {
        // Send a reconnect message back to the Activity
            Message msg = mHandler.obtainMessage(cBluetooth.MESSAGE_TOAST);
            Bundle bundle = new Bundle();
            bundle.putString(WebAppInterface.TOAST, "Connection lost. Reconnecting...");
            msg.setData(bundle);
            mHandler.sendMessage(msg);
            connect(mSavedDevice,true);     
        } else {
        mConnectionLostCount = 0;
        Message msg = mHandler.obtainMessage(cBluetooth.MESSAGE_TOAST);
        Bundle bundle = new Bundle();
        bundle.putString(WebAppInterface.TOAST,"Device connection was lost!");
        msg.setData(bundle);
        mHandler.sendMessage(msg);
        cBluetooth.this.stop();
        }
    }
    

    我希望您可以根据自己的情况对其进行调整。您也可以查看此链接,它们对我帮助很大:

    1. remote control example
    2. connection dying solution
    3. Bluetooth Service example to get inspired from

    【讨论】:

      【解决方案3】:

      我遇到了类似的问题,并花了一些时间调试这个问题。我正在运行 Android 4.3,发现 BluetoothChat 示例代码所需的唯一基本修改是设置:

      MY_UUID_SECURE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
      

      我正在尝试连接到 HC-05 蓝牙模块,并且我相信它使用此 UUID 指示的 SPP 配置文件。您可以使用这行代码查询设备的 UUID:

      UUID uuid = device.getUuids()[0].getUuid();
      

      根据您连接的设备类型验证 UUID 并查看它是否与有意义的配置文件匹配。

      MY_UUID_SECURE = uuid;
      

      UUID 可能指示不同类型的设备配置文件,具体取决于您连接的内容。使用正确的 UUID,我仍然能够运行 AcceptThread 代码并作为 BluetoothServerSocket 侦听,没有任何问题。我希望这会有所帮助,但是,我对 Android 和蓝牙开发还比较陌生,所以如果我的假设是错误的,请纠正我。

      【讨论】:

        【解决方案4】:

        遇到了类似的问题。通过使用 17 作为构建目标的 4.2 SDK 构建来修复其中的一些问题。

        【讨论】:

        • 嘿安德烈:“其中一些”是什么意思?某些设备或某些类型的设备?您是否介意分享一下您身边的设备是什么?
        【解决方案5】:

        我终于找到了解决办法。

        事实证明,这不是新蓝牙驱动程序中的错误。这是蓝牙示例应用程序中未考虑的极端情况,更具体地说,是由 Android SDK 提供的 BluetoothChat 项目。

        在BluetoothChat 示例项目中的蓝牙服务代码中,当连接失败或丢失时,它总是重新启动服务以重新启动监听模式。手机作为服务器是没有问题的,但是在某些情况下手机作为客户端,一旦进入监听模式,就无法连接到其他服务器。因为在“连接”函数中,它不会取消 (In)SecureAcceptThread。所以本质上你正在作为服务器监听其他连接,同时尝试作为客户端连接到其他服务器。这很矛盾。

        解决此问题的方法是,如果您确定您的手机不会被用作服务器监听传入连接,则只需删除代码以在连接失败或停止时重新启动监听模式。

        【讨论】:

        • 嗯,我在使用 Nexus 7 和自定义蓝牙设备时遇到了同样的问题,即使我根本没有使用监听模式。
        • 我在这里发布了我的工作代码gist.github.com/cnbuff410/5675975 它主要基于示例代码。但它适用于我目前拥有的所有手机
        【解决方案6】:

        我的 Nexus 4 遇到了同样的问题。

        就我而言,我认为问题在于 SDP 服务发现协议。设备和服务器必须为某个服务使用相同的 UUID。

        我在我的应用程序中使用 SPP(串行端口协议)。因此,我将 BluetoothChat 示例代码中的 UUID 从“fa87c0d0-afac-11de-8a39-0800200c9a66”更改为 SPP“00001101-0000-1000-8000-00805F9B34FB”。现在好了。

        我在 BluetoothChatService.start() 中禁用了 acceptThread 的监听代码。现在更简洁了。希望它会有所帮助。

        【讨论】:

          【解决方案7】:

          我在 4.2.2 上也有同样的经历。

          但我发现蓝牙堆栈只有在我的应用程序失败或在没有正确清理资源(套接字和/或流)的情况下被终止后才开始出现异常。在此之前,当我正确关闭我的应用程序时,它可以正常工作。

          例如,当我关闭套接字然后终止应用程序时,我可以启动它并再次正常连接。如果我在之前没有关闭套接字的情况下杀死了我的应用程序,那该死的,我必须重新启动设备才能使其再次工作。

          看来新的 Android 蓝牙堆栈在隐式清理机制中存在一些错误。当应用程序崩溃时,Android 应该清理没有发生的打开的蓝牙资源。

          我的蓝牙管理代码在应用程序子类中。没有办法 - 或者我看不到 - 如何挂钩应用程序销毁并进行清理。

          任何建议表示赞赏

          编辑:

          我做了一个相当混乱的解决方法。

          我创建了包含单个远程服务的单独应用程序。我将所有通信代码(套接字和流的打开、读取、写入、关闭)移到了这个远程服务中。然后,如果主应用程序崩溃或被杀死,该服务仍在运行。当我再次启动应用程序时,连接仍然正常。 从蓝牙输入流中读取的字节通过标准服务消息传递到主应用程序。就我而言,这没问题,因为我传输的数据量非常少。

          当包含该服务的应用程序被杀死时,同样的混乱也会发生。

          【讨论】:

            【解决方案8】:

            我也面临同样的问题。这对我有用:

            try {
                Thread.sleep(1000); 
            }
            catch(Exception e3)
            {
                Toast.makeText(getApplicationContext(), "wa ni sud sa thread sleep!", Toast.LENGTH_SHORT).show();
            }
            btSocket.close();
            

            【讨论】:

              猜你喜欢
              • 2015-10-25
              • 2012-06-22
              • 1970-01-01
              • 2023-03-18
              • 1970-01-01
              • 1970-01-01
              • 2014-04-27
              • 1970-01-01
              • 2011-02-09
              相关资源
              最近更新 更多