2

我有两个不同的蓝牙打印机。Bixolon SPP-R200 和富士通 FTP-628WSL110。我可以分别连接到它们(使用三星 Galaxy SII)打印、断开连接和重新连接就好了。但是,如果我关闭 Bixolon 并尝试与 Fujitsu 配对(之前未配对,Bixolon 仍然配对),那么在尝试连接到创建的套接字时它会失败。反过来也一样。

这是错误消息:

07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380): Failed to connect to rfcomm socket.
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380): java.io.IOException: Service discovery failed
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380):  at android.bluetooth.BluetoothSocket$SdpHelper.doSdp(BluetoothSocket.java:406)
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380):  at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:217)
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380):  at MyApp.BluetoothConnection.connect(BluetoothConnection.java:171)
07-02 13:00:11.040: E/MyApp.BluetoothConnection(9380):  at MyApp.AbstractBluetoothPrinter.connect(AbstractBluetoothPrinter.java:34)

这是进行连接尝试的代码,在解释的情况下失败的行是 btSocket.connect(); - 例外见上文:

/** Is set in connect() */
private BluetoothSocket btSocket = null;
/** Is set prior to connect() */
private BluetoothSocket btDevice;

public boolean connect(){

        try {
            btSocket = btDevice.createRfcommSocketToServiceRecord("00001101-0000-1000-8000-00805F9B34FB");
            if (btDevice.getName().startsWith("FTP")) {
                //Special treatment for the fujitsu printer
                SystemClock.sleep(1000);
            }
        } catch (Throwable e) {
            LogCat.e(TAG, "Failed to create rfcomm socket.", e);
            return false;
        }

        try {
            // Stop Bluetooth discovery if it's going on
            BluetoothHandler.cancelDiscovery();
            // This fails under the described circumstances
            btSocket.connect();
        } catch (Throwable e) {
            LogCat.e(TAG, "Failed to connect to rfcomm socket.", e);
            return false;
        }

        // Obtain streams etc...
}

我使用相同的UUID 连接到两个设备(但一次只打开一个设备,它们不会同时打开),SDK API 中众所周知的 SPP UUID:

00001101-0000-1000-8000-00805F9B34FB

这让我想知道:难道我需要为每个设备使用不同的 UUID?如果是的话,有什么想法吗?

4

1 回答 1

10

好的,经过几天尝试不同的解决方案,我现在可以在上述打印机之间切换。由于我不完全确定我的哪些措施是成功的原因,所以我将它们全部列出,所以偶然发现这篇文章的人会对如何解决他的蓝牙问题有一些线索。但是我很确定一件事:您不需要不同的 UUID 来连接两台不同的打印机 - 您可以使用相同的 UUID(但我只打开过其中一个)。

我缓存了上次打印到的设备 - 但是与以前不同的是,我不再缓存实际的BluetoothDevice,而是只缓存它的 MAC 地址,该地址可通过以下方式获得:

BluetoothDevice bluetoothDevice; 

//Obtain BluetoothDevice by looking through paired devices or starting discovery

bluetoothDevice.getAddress(); 

getAddress()返回一个字符串:设备的硬件地址。我缓存了那个mac地址,下次用户想要打印时,我将缓存的mac地址与所有配对打印机的mac地址进行匹配——如果mac地址与其中一个匹配,我会尝试连接到该打印机。如果失败,我会重置我的缓存mac地址并尝试通过首先检查我的配对设备是否可以连接来找到另一个设备(如果我可以成功连接,我会相应地更新我的缓存mac地址),如果失败我开始一个寻找其他潜在设备的蓝牙发现。

现在,为了不让我的一台打印机打开任何套接字连接,我的例程如下(我将省略我在每个调用周围的 try-catch 以简化阅读):

创建套接字

BluetoothSocket btSocket = btDevice.createRfcommSocketToServiceRecord(MY_UUID);

MY_UUID 指的是众所周知的用于连接 SPP 设备的 UUID:

00001101-0000-1000-8000-00805F9B34FB

如果套接字创建失败(这种情况很少见,如果发生这种情况很可能是由于权限不足或蓝牙被禁用/不可用),我们无法继续进行,因为我们需要一个套接字来连接。因此,在您的 catch 块中,您应该触发 disconnect 方法(稍后会详细介绍)。

连接到创建的套接字

bSocket.connect();

如果连接失败,我们将无法继续进行,因为我们需要一个有效的套接字连接来获取输入和输出流。因此,在您的 catch 块中,您应该触发 disconnect 方法(稍后会详细介绍)。

获取输入输出流

下一步是从套接字获取输入和输出流。我在一个 for 循环中执行此操作,该循环运行了几次(5 次就足够了) - 在每次迭代中,我检查是否有输出流,如果没有,我尝试获取它,与输入流相同。在循环结束时,我检查我是否有两个流,如果是,我退出循环(以及整个连接方法),如果没有,我继续循环并重试。通常我在第一次循环迭代中得到两个流,但有时我需要两个或三个迭代来获得两个流。

如果我到达循环声明之后的代码,我显然没有得到我的流或其他错误。此时连接被认为失败了,我执行了我的断开代码(它会清理打开的流和套接字,稍后会详细介绍)。

读/写

现在您已经连接到目标蓝牙设备,您可以执行读写操作。完成后,您应该通过关闭所有流和套接字来进行清理,下一段将详细介绍:断开连接。请记住:如果在读/写操作期间发生异常,请务必触发断开连接方法以清理您的资源。如果您的打印机需要某种初始化命令,请务必在连接到打印机之后和执行读/写操作之前立即发送该命令。

断开连接

通常有两种情况您应该断开连接:

  • 完成读/写操作后
  • 如果沿途某处发生异常,清理您的资源

关闭您的信息流

你要做的第一件事是清理你的流,检查你的输入和输出流,如果它们不为空,关闭它们并将它们设置为空。确保将每个操作(关闭输入流、关闭输出流等)包装到自己的 try-catch 中,否则无法进行一次清理(因为引发异常)将跳过所有其他清理措施。

关闭插座

现在您已经确保您的输入流已被清理,继续关闭您的套接字连接,然后将其设置为 null。

还有一件事:我的断开方法的开头和结尾都有一个 Thread.sleep 。一开始的时间约为 2.5 秒(= 2500 毫秒),目的是确保打印机没有其他任何事情发生(例如挂起的读/写操作或打印机仍在打印等)。第二个 Thread.sleep 在我的断开方法结束时,大约 800 毫秒长。最后睡眠的原因与我在关闭一个套接字后立即尝试打开一个新套接字时遇到的问题有关。有关更多详细信息,请参阅此答案

问题?

如果有人对我的 OP 或我的回答有任何疑问,请在评论中告诉我,我会尽力回答。

于 2012-07-06T08:20:57.703 回答