与IntentService的蓝牙连接问题

我需要从我的Android应用程序通过蓝牙(到Arduino)传输一些数据。 我不读/从Arduino收回任何东西。 对于我单线程的需求,我去了一个IntentService。 配对后,我的代码工作正常,我第一次连接和发送数据。 发送数据后没有错误,我断开连接。 但是当我尝试连接第二次以后,当我尝试myBluetoothSocket.connect()时出现以下错误:

读取失败,套接字可能closures或超时,请阅读ret:-1

唯一的解决办法是closuresArduino设备并重新连接(如果我强制停止应用程序并尝试重新连接,这并不会有帮助)。

请注意,如果我产生了2个线程(一个用于读写每个线程),无论连接和发送数据多less次(从而certificateArduino没有错,“阻止”旧连接),一切正常。

这是我的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和三星S5设备(分别运行5.1和5.0)上进行了testing。

Solutions Collecting From Web of "与IntentService的蓝牙连接问题"

当您第二次尝试连接时,必须再次创build相应的套接字。

另外,你必须考虑Arduino是一个缓慢的平台,closures连接和你可以再次打开它之间可能会有一些相当大的延迟。

我不确定它为什么有效,但是这个方法终于奏效了:

 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()方法。 您需要像从前那样从onHandleIntent(Intent)调用cleanup() ,否则套接字将无限期地保持打开状态。 由于您将其打开,因此无法再次连接。

Android的蓝牙堆栈似乎与应用程序生命周期无关:即使强制停止应用程序,套接字也将保持打开状态。 在您当前的情况下,要closures套接字,请在“设置”中禁用Bluetooth。