Проблемы с подключением Bluetooth с помощью IntentService

Мне нужно передать некоторые данные из моего приложения Android через Bluetooth (в Arduino). Я ничего не читаю и не получаю от Ардуино. Для моих однопоточных потребностей я пошел с IntentService. После спаривания мой код отлично работает в первый раз, когда я подключаю и отправляю данные. Я отключусь после отправки данных без ошибок. Но когда я пытаюсь подключиться во второй раз, я получаю следующую ошибку при попытке myBluetoothSocket.connect ():

Read failed, сокет может быть закрыт или таймаут, read ret: -1

Единственное решение – отключить устройство Arduino и снова подключиться (это не поможет, если я заблокирую приложение и попробую повторно подключиться).

Обратите внимание, что все работает нормально, если я создаю 2 потока (один для чтения и записи каждого), независимо от того, сколько раз я подключаю и отправляю данные (тем самым доказывая, что на стороне Arduino нет ничего плохого, «сдерживая» старое соединение).

Вот мой Android-код:

import android.app.IntentService; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.Intent; import android.content.Context; import android.os.Build; import android.os.ParcelUuid; import android.widget.Toast; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Method; import java.util.UUID; public class DataTransmissionService extends IntentService { private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); private static final String TAG = "DataTransmissionService"; private BluetoothAdapter btAdapter = null; private BluetoothSocket btSocket = null; private OutputStream outStream = null; private BluetoothDevice device = null; public DataTransmissionService() { super("DataTransmissionService"); } @Override protected void onHandleIntent(Intent intent) { cleanup(); if (intent != null){ btAdapter = BluetoothAdapter.getDefaultAdapter(); pairedDeviceAddress = "already_paired_device_mac_addr"; try { log.d(TAG, pairedDeviceAddress); device = btAdapter.getRemoteDevice(pairedDeviceAddress); log.d(TAG, "Device bond state : " + device.getBondState()); } catch (Exception e) { log.e(TAG, "Invalid address: " + e.getMessage()); return; } try { btSocket = createBluetoothSocket(device); } catch (IOException e) { log.e(TAG, "Socket creation failed: " + e.getMessage()); return; } try { if (!btSocket.isConnected()) { btSocket.connect(); log.d(TAG, "Connected"); } else { log.d(TAG, "Already Connected"); //flow never reaches here for any use case } } catch (IOException e) { log.e(TAG, "btSocket.connect() failed : " + e.getMessage()); return; } try { outStream = btSocket.getOutputStream(); } catch (IOException e) { log.e(TAG, "Failed to get output stream:" + e.getMessage()); return; } sendData("test"); //cleanup(); called in onDestroy() } } @Override public void onDestroy(){ cleanup(); //notify ui super.onDestroy(); } private void cleanup(){ try { if (outStream != null) { outStream.close(); outStream = null; } } catch (Exception e) { log.e(TAG, "Failed to close output stream : " + e.getMessage()); } try { if (btSocket != null) { btSocket.close(); btSocket = null; } }catch (Exception e) { log.e(TAG, "Failed to close connection : " + e.getMessage()); } } private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException { /*if(Build.VERSION.SDK_INT >= 10){ try { final Method m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", new Class[] { UUID.class }); return (BluetoothSocket) m.invoke(device, MY_UUID); } catch (Exception e) { log.e(TAG, "Could not create Insecure RFComm Connection",e); } }*/ return device.createRfcommSocketToServiceRecord(MY_UUID); } private void sendData(String message) { byte[] msgBuffer = message.getBytes(); log.d(TAG, "Sending : " + message); try { outStream.write(msgBuffer); } catch (IOException e) { log.e(TAG, "failed to write " + message); } } } 

Я тестировал устройства Nexus 5 и Samsung S5 (работает соответственно 5.1 и 5.0).

Когда вы попытаетесь подключиться во второй раз, вам нужно снова создать соответствующий сокет.

Также вы должны подумать, что Arduino – это медленная платформа, может быть некоторая значительная задержка между закрытием соединения и возможностью открыть его снова.

Я не уверен, почему это работает, но этот подход, наконец, сработал:

 private BluetoothSocket createBluetoothSocket(BluetoothDevice bluetoothDevice) throws IOException { try { Method m = bluetoothDevice.getClass().getMethod( "createRfcommSocket", new Class[] { int.class }); btSocket = (BluetoothSocket) m.invoke(bluetoothDevice, 1); } catch (Exception e) { e.printStackTrace(); } return btSocket; } 

Метод onDestroy() вызывается только при onDestroy() сборщика мусора. Вам нужно вызвать cleanup() из onHandleIntent(Intent) как вы это делали раньше, иначе сокет останется открытым неограниченное время. Поскольку вы оставили его открытым, вы не можете подключиться снова.

Стек Bluetooth для Android кажется агностиком жизненного цикла приложения: сокет останется открытым, даже если вы принудительно остановите приложение. В вашем текущем сценарии, чтобы закрыть сокет, отключите функцию Bluetooth в настройках.

Intereting Posts
Как распечатать запрос, выполненный методом query () для android Android: как загружать и отображать большие изображения (размер A0) – например, карта google? Как открыть папку «Мои файлы» в Android программно (с использованием Intent)? Зачем устанавливать заданную форму в макете фона? Интерфейс Android для нескольких устройств Как получить мой контекст активности? Определение того, какое слово щелкнуть в текстовом виде android Как добавить кнопку непосредственно в Уведомление на Android Wear Как предотвратить задержку пользовательского интерфейса при обновлении уведомления при загрузке файла? Непосредственно откройте экран рейтинга Play Store из нашего приложения в Android Android Не удается подключиться к службе камеры Java.lang.NullPointerException в doInBackground помещает HashMap в ArrayList Модификация хранилища Android Выровнять значения счетчика вправо, а не влево Разрешить стили стилизовать