Android: переключение между устройствами SPP Bluetooth

У меня есть два разных принтера Bluetooth. Биксолон SPP-R200 и Fujitsu FTP-628WSL110. Я могу подключиться к каждому из них по отдельности (используя Samsung Galaxy SII) распечатать, отключить и переподключить просто отлично. Однако, если я выключаю биксолон и пытаюсь выполнить сопряжение с Fujitsu (ранее непарным, биксолон по-прежнему сопряжен), то происходит сбой при попытке подключения к созданному сокету. То же самое наоборот.

Вот сообщение об ошибке:

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...
}

Я используюsame UUID для подключения кboth устройства (но одновременно включается только одно устройство, они никогда не включаются одновременно), хорошо известный SPU UUID из API SDK:

00001101-0000-1000-8000-00805F9B34FB

Что заставляет меня задуматься: неужели мне нужен разный UUID для каждого устройства? Если да, то какая идея?

Ответы на вопрос(1)

Решение Вопроса

после нескольких дней попыток найти разные решения, я теперь могу переключаться между вышеупомянутыми принтерами. Поскольку я не совсем уверен, какая из моих мер послужила причиной успеха, я перечислю их все, так что кто-то, наткнувшись на этот пост, будет иметь некоторые подсказки о том, как исправить свои проблемы с Bluetooth. Однако в одном я совершенно уверен: вам не нужны разные 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-адрес соответствующим образом), и если это не удается, я запускаю поиск Bluetooth ищет другие потенциальные устройства.

Теперь, чтобы не оставлять никаких соединений сокетов открытыми для одного из моих принтеров, моя процедура выглядит следующим образом (я опущу ловушки, которые я обертываю вокруг каждого вызова, чтобы облегчить чтение):

Create the socket

BluetoothSocket btSocket = btDevice.createRfcommSocketToServiceRecord(MY_UUID);

MY_UUID относится к хорошо известному UUID, используемому для подключения к устройствам SPP:

00001101-0000-1000-8000-00805F9B34FB

Еслисоздание сокета происходит сбой (что случается редко, и если это происходит, скорее всего, из-за недостаточных разрешений или из-за того, что Bluetooth отключен / недоступен), мы не можем продолжать, поскольку нам нужен сокет для подключения. Следовательно, в вашем блоке catch вы должны активировать метод отсоединения (об этом позже).

Connect to the created socket

bSocket.connect();

Если соединение завершится неудачно, мы не сможем продолжить, так как нам нужно правильное сокетное соединение для получения входных и выходных потоков. Следовательно, в вашем блоке catch вы должны активировать метод отсоединения (об этом позже).

Obtain the input and output stream

Следующим шагом будет получение входного и выходного потоков из сокета. Я делаю это в цикле for, который выполняется пару раз (5 раз должно быть достаточно) - на каждой итерации я проверяю, есть ли у меня выходной поток, если нет, я пытаюсь получить его, то же самое для входного потока. В конце цикла я проверяю, есть ли у меня оба моих потока, если да, я выхожу из цикла (И весь метод соединения), если нет, я продолжаю цикл и пытаюсь снова. Обычно я получаю оба своих потока в первой итерации цикла, однако иногда мне нужно две или три итерации, чтобы получить оба потока.

Если я получаю код, который следует после объявления цикла, я, очевидно, не получаю свои потоки, или что-то еще пошло не так. На этом этапе соединение считается сбойным, и я выполняю код отключения (который очищает открытые потоки и сокеты, подробнее об этом позже).

Read/Write

Теперь, когда у вас есть соединение с целевым устройством Bluetooth, вы можете выполнять операции чтения и записи. Как только вы закончите, вы должны очистить, закрыв все потоки и сокеты, подробнее об этом в следующем параграфе: Отключение. Помните: если во время операций чтения / записи возникает исключение, обязательно запустите метод отсоединения, чтобы очистить ваши ресурсы. Если вашему принтеру требуется какая-либо команда инициализации, обязательно отправьте ее сразу после подключения к принтеру и перед выполнением операций чтения / записи.

Disconnecting

Обычно есть два случая, когда вы должны отключиться:

Once you're done with your read/write operations If an exception occurred somewhere along the way, to cleanup your resources

Close your streams

Первое, что вы хотите сделать, это очистить ваши потоки, проверить оба, ваш входной и выходной потоки, если они не равны NULL, закройте их и установите для них значение NULL. Обязательно оберните каждую операцию (закрытие входного потока, закрытие выходного потока и т. Д.) В свой собственный метод try-catch, так как в противном случае не удастся выполнить одну очистку (поскольку возникает исключение) пропустит все другие меры очистки.

Close the socket

Теперь, когда вы убедились, что ваши входные потоки очищены, перейдите к закрытию вашего сокетного соединения и установите для него значение null после этого.

Еще одна вещь: у меня есть Thread.sleep в начале и в конце моего метода отключения. Первый в начале занимает около 2,5 секунд (= 2500 миллисекунд), его цель - убедиться, что с принтером больше ничего не происходит (например, ожидающие операции чтения / записи или принтер все еще печатает и т. Д.). Второй Thread.sleep находится в конце моего метода отключения и имеет длину около 800 миллисекунд. Причина этого сна в конце связана с проблемами, которые возникли у меня при попытке сразу открыть новый сокет сразу после его закрытия. Для более подробной информации, пожалуйста, обратитесь кэтот ответ.

Questions?

Если у кого-то есть вопросы, связанные с моим ОП или моим ответом, сообщите мне об этом в комментариях, и я постараюсь ответить на них.

 25 февр. 2016 г., 13:29
Не могли бы вы проверить этоquestion пожалуйста? : D
 AgentKnopf26 февр. 2016 г., 15:19
@ Скизо я так и сделал, и звучит так, будто ответ здесь именно то, что тебе нужно? Если это не работает для вас, пожалуйста, дайте мне знать, в чем проблема.
 26 февр. 2016 г., 15:32
Я использую этот код, это более или менее пример документов Androidrepo но это все еще говорит, что это не связано
 AgentKnopf27 февр. 2016 г., 17:48
@Skizo: ссылка не работает xD. Вы пытались прочитать ответ, приведенный здесь, и соответственно скорректировать свой код? Кроме того - вы проверили файлы журналов? Обязательно обратите внимание на исключения / причины того, почему это не работает.

Ваш ответ на вопрос