Android 4.2上蓝牙RFCOMM连接无法连续建立

10
我有一个应用程序,通过蓝牙的RFCOMM与自定义设备通信。通信代码基于BluetoothTalk示例项目。它以前在Galaxy S3、Galaxy S2、Galaxy Note和Nexus 7上运行良好,但最近,Nexus 7升级到Android 4.2后,出现以下问题:
1. 当您首次使用该应用程序建立连接时(即设备刚开启并且应用程序刚启动),可以正常获取数据。
2. 然后,如果您停止通信,并尝试重新启动,则通信会失败,显示错误“java.io.IOException: bt socket closed, read return: -1”。从那时起,无论您尝试多少次重新连接,它都始终失败。
3. 使其再次工作的唯一方法是,如果您重新启动自定义设备和应用程序,然后尝试连接,通信将变为正常状态。但是,一旦您停止并重新启动通信,它就会一直失败。
我借了一台安装有Android 4.2的Nexus 4测试,问题仍然存在。
这真的很烦人,因为我们设备的主要价值依赖于蓝牙RFCOMM应用程序。我仔细检查了Android 4.2中关于蓝牙的文档,并没有看到任何重大变化。我对我方面的代码非常有信心,因为它适用于没有运行4.2的任何Android设备。
如果您有任何提示或建议,我们将不胜感激。该设备需要在12月初进行演示,我们真的希望尽快解决这个问题。
编辑:现在4.2.1已发布,问题仍未解决。我们至少可以确认是否正在解决并且很快就会修复吗?
8个回答

6
这并不能帮到你什么,但请注意谷歌在4.2版本中引入了全新的蓝牙栈。这本应是一件好事情 - 就我的经验来说,使用旧的 Bluez 时,Android 从用户和开发者的角度看都无法可靠地运行,因此我很高兴听到他们进行了全面重写。
我想我唯一能说的就是,听起来你遇到了新栈中的某个 bug 或问题。很遗憾听到新栈也存在问题。
关于你的演示,请注意谷歌为所有 Nexus 设备发布固件镜像(https://developers.google.com/android/nexus/images),将其刷入设备相当容易。因此,我建议你提交一个 bug 报告,然后将设备升级至4.1.2版。

很有趣。但如果是这样的话,他们应该公开承认并给出预计的错误修复日期。此时此刻,我更加好奇的是,这是否确实是他们的错误,或者是否有任何快速技巧来解决这个问题。 - cnbuff410
另一方面,有一些应用似乎可以与4.2.1和BT连接配合使用 - 这是我其中一个拥有4.2.1的应用程序用户告诉我的(很不幸,我的应用程序也会因为上述错误而崩溃,并且仍未找到“窍门”)。 - user387184
这些应用程序是否使用SPP配置文件?我尝试了4.2.2,似乎问题还没有解决。 - cnbuff410

1
在我的测试中也遇到过这个问题。在BluetoothChat示例代码中,你应该查看connectionLost方法。我不记得是否有任何变量来保留失去连接的次数,但你可以自己添加。在connectionLost方法中,检测失去连接的次数是否小于一个预定义的数字(在我的情况下是3)。如果为真,则使用mHandler向UI发送消息(一条toast)并再次调用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. 蓝牙服务示例以供参考

1

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

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

我正在尝试连接HC-05蓝牙模块,我认为它使用SPP配置文件,正如此UUID所示。您可以使用以下代码查询设备的UUID:

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

验证UUID并查看是否与您连接的设备类型相匹配的配置文件相匹配。

MY_UUID_SECURE = uuid;

UUID可能表示不同类型的设备配置文件,具体取决于您要连接的内容。使用适当的UUID,我仍然能够运行AcceptThread代码并且作为BluetoothServerSocket进行侦听而没有任何问题。希望这可以帮助您,但是,我对Android和蓝牙开发相对较新,因此如果我的假设有误,请纠正我。

0

我也遇到了同样的问题。这个方法对我有效:

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

0

我终于找到了解决方案。

原来这并不是新蓝牙驱动程序中的 bug,而是 Bluetooth 示例应用程序中未考虑的特殊情况,更具体地说,是由 Android SDK 提供的 BluetoothChat 项目引起的。

在 BluetoothChat 示例项目的 Bluetooth 服务代码中,当连接失败或丢失时,它总是重新启动服务以重新开始监听模式。当手机用作服务器时,这并不成问题,但在某些情况下,当手机用作客户端时,一旦进入监听模式,就无法连接到其他服务器。因为在“连接”函数中,它不会取消 (In)SecureAcceptThread。因此,实际上您正在作为服务器监听其他连接,同时尝试作为客户端连接其他服务器,这是相互冲突的。

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


2
嗯,我在Nexus 7和自定义蓝牙设备上遇到了同样的问题,即使我根本没有使用监听模式。 - Blackhex
我在这里发布了我的工作代码https://gist.github.com/cnbuff410/5675975它主要基于示例代码。但目前它可以在我所有的手机上运行。 - cnbuff410

0

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

在我的情况下,我认为问题在于SDP服务发现协议。设备和服务器必须使用相同的UUID来识别某个服务。

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

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


0
遇到了类似的问题。通过使用4.2 SDK和将构建目标设置为17来解决其中一些问题。

嘿,安德烈:你所说的“一些设备”是指哪些设备?是某些类型的设备吗?另外,你介意分享一下你那边正在使用的设备是什么吗? - cnbuff410

0

我在4.2.2上有同样的经验。

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

例如,当我关闭套接字然后杀死应用程序时,我可以正常启动并重新连接。如果我在先前未关闭套接字的情况下杀死我的应用程序,则会出现问题,我必须重新启动设备才能使其再次工作。

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

我的蓝牙管理代码位于Application子类中。没有办法 - 或者我看不到任何方法 - 如何挂钩Application destroy并进行清理。

任何建议都将不胜感激

编辑:

我已经做了相当混乱的解决方法。

我创建了一个单独的应用程序来包含一个远程服务。我将所有通信代码(socket和流的打开、读取、写入、关闭)移动到这个远程服务中。那么,如果主应用程序崩溃或被杀死,该服务仍在运行。当我再次启动应用程序时,连接仍然保持。

通过标准服务消息将从蓝牙输入流中读取的字节转移到主应用程序中。对于我的情况来说,这是可以接受的,因为我传输的数据量非常小。

尽管如此,当包含服务的应用程序被终止时,同样的消息会发生。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接