10

我有一个应用程序,它通过蓝牙通过 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 已经发布,但问题仍未解决。我们至少可以确认它是否正在工作并且很快就会修复吗?

4

8 回答 8

6

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

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

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

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

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

于 2012-11-20T00:39:00.393 回答
1

它也发生在我的测试中。我是 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. 遥控器示例
  2. 连接死机解决方案
  3. 从中获得灵感的蓝牙服务示例
于 2013-10-15T11:42:33.343 回答
1

我有一个类似的问题,并花了一些时间调试这个问题。我正在运行 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 和蓝牙开发相对较新,所以如果我的假设是错误的,请纠正我。

于 2014-01-12T02:35:36.290 回答
0

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

于 2013-01-04T12:56:45.380 回答
0

我终于找到了解决方案。

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

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

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

于 2013-04-04T16:17:42.590 回答
0

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

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

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

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

于 2013-07-03T09:08:15.840 回答
0

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

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

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

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

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

任何建议表示赞赏

编辑:

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

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

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

于 2013-10-21T22:23:08.523 回答
0

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

try {
    Thread.sleep(1000); 
}
catch(Exception e3)
{
    Toast.makeText(getApplicationContext(), "wa ni sud sa thread sleep!", Toast.LENGTH_SHORT).show();
}
btSocket.close();
于 2015-01-06T05:59:18.183 回答