我编写了一个基于bluetoothChat的简单应用程序。我使用SPP配置文件在电话和蓝牙模块之间进行通信。电话始终会启动通信。该应用程序在使用Nexus 3和Samsung Galaxy 3的Android 4.2上完美运行。在更新至Android 4.3之后,该应用程序不再起作用。我一直保持连接状态,可以发送输出流并接收正确的数据,但是在执行第一个outputstream命令后,应用程序总是在约6秒后断开连接。如下面的logcat所示,看起来输入流上存在计时器问题。
08-23 14:10:00.726: D/mems(23193): STEVAL-MKI106V1 08-23 14:10:00.804: D/Main Activity(23193): firmware version*setdb106V1 08-23 14:10:00.812: D/Main Activity(23193): sent message*setdb106V1 08-23 14:10:00.812: D/BluetoothMEMSCommunication(23193): dans write3 08-23 14:10:00.812: D/BluetoothMEMSCommunication(23193): envoi stream 08-23 14:10:05.812: W/bt-btif(20368): dm_pm_timer expires 08-23 14:10:05.812: W/bt-btif(20368): dm_pm_timer expires 0 08-23 14:10:05.812: W/bt-btif(20368): proc dm_pm_timer expires 08-23 14:10:11.656: E/bt-btm(20368): btm_sec_disconnected - Clearing Pending flag 08-23 14:10:11.656: W/bt-btif(20368): invalid rfc slot id: 15 08-23 14:10:11.656: I/connection(23193): connectionlost
什么是dm_pm_timer?我尝试用安全和不安全的rfcom连接另一种方式。我知道蓝牙聊天尚未针对接收缓冲区进行优化,因此我对其进行了修改,并非没有效果。我也对输出流使用了flush命令,但也没有效果。
package com.meneujj.memsbtbis; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.UUID; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.widget.Toast; public class BluetoothMEMSCommunication { // debugging private static final String TAG = "BluetoothMEMSCommunication"; private static final boolean D = true; // eMotion BT h as this standard UUID private static final UUID STANDARD_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); // Member fields private final BluetoothAdapter mAdapter; private final Handler mHandler; private int mState; private int handlerCalling; private ConnectThread mConnectThread; private ConnectedThread mConnectedThread; // Constants they indicate the current connection state public static final int STATE_NONE = 0; public static final int STATE_CONNECTED = 3; // now connected to a remote device // constructor. Prepares a new Bluetooth Connection // context The UI Activity Context // handler an Handler to send messages back to the UI Activity public BluetoothMEMSCommunication(Context context, Handler handler, int i) { mAdapter = BluetoothAdapter.getDefaultAdapter(); mState = STATE_NONE; mHandler = handler; handlerCalling = i; } private synchronized void setState(int state) { mState = state; Log.d(TAG, Integer.toString(mState)); mHandler.obtainMessage(MainActivityMemsBT.MESSAGE_STATE_CHANGE, state, -1).sendToTarget(); } public synchronized void connect(BluetoothDevice device) { // start the thread to connect with the given device if (mConnectThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } // cancel any thread currently running a connection if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } Log.d(TAG,"routine connect lancee"); mConnectThread = new ConnectThread(device); mConnectThread.start(); } private void ConnectionLost() { // Send a failure message back to the activity Message msg = mHandler.obtainMessage(MainActivityMemsBT.CONNECTION_LOST_MESSAGE); Bundle bundle = new Bundle(); bundle.putString(MainActivityMemsBT.TOAST_CONNECTION_LOST, "Device connection was lost"); msg.setData(bundle); mHandler.sendMessage(msg); Log.i("connection","connectionlost"); setState(STATE_NONE); StopAllThreads(); } public synchronized void StopAllThreads() { if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } setState(STATE_NONE); } public synchronized void connected(BluetoothSocket socket, BluetoothDevice device, final String socketType) { // cancel the thread they completed the connection if (mConnectThread != null) { mConnectThread.cancel(); mConnectThread = null; } // Cancel any thread currently running a connection if (mConnectedThread != null) { mConnectedThread.cancel(); mConnectedThread = null; } // Start the thread to manage the connection and perform transmission mConnectedThread = new ConnectedThread(socket, socketType); mConnectedThread.start(); // Send the name of the connected device back to the UI activity Message msg = mHandler.obtainMessage(MainActivityMemsBT.MESSAGE_DEVICE_NAME); Bundle bundle = new Bundle(); bundle.putString(MainActivityMemsBT.DEVICE_NAME, device.getName()); msg.setData(bundle); mHandler.sendMessage(msg); setState(STATE_CONNECTED); } public void write(byte[] out) { // create temporary object ConnectedThread r; Log.d(TAG,"dans write" + Integer.toString(mState)); // synchronize a copy of the ConnectedThread synchronized (this) { if (handlerCalling == 2) setState(STATE_CONNECTED); if (mState != STATE_CONNECTED) { Log.d(TAG, "different de STATE_CONNECTED"); Log.i(TAG, Integer.toString(handlerCalling)); return;} r= mConnectedThread; } r.write(out); }
有办法解决吗?或我的代码中有任何明显的错误
谢谢
// Thread runs while attempting to an an outgoing connection with a device. // it runs straight through; the connection either succeeds or fails. private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; private String mSocketType; public ConnectThread(BluetoothDevice device) { mmDevice = device; BluetoothSocket tmp = null; try { tmp = device.createRfcommSocketToServiceRecord(STANDARD_UUID); //tmp = device.createInsecureRfcommSocketToServiceRecord(STANDARD_UUID); /* try { Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}); try { tmp = (BluetoothSocket) m.invoke(device, 1); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } */ } catch (IOException e) { } mmSocket = tmp; } public void run () { setName("ConnectThread" + mSocketType); mAdapter.cancelDiscovery(); try { mmSocket.connect(); } catch (IOException e) { try { mmSocket.close(); } catch (IOException e2) { Log.e(TAG, "unable to close() " + mSocketType + "socket during connection failure", e2); } return; } // reset the CoonectThread because the job is over synchronized (BluetoothMEMSCommunication.this) { mConnectThread = null; } connected(mmSocket, mmDevice, mSocketType); } public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } // close connectThread class } private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket, String socketType) { mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { ConnectionLost(); } mmInStream = tmpIn; mmOutStream = tmpOut; } // Thread to listen to input sockets public void run() { Log.i(TAG, "Begin mConnectedThread"); byte[] buffer = new byte[1024]; // int bytes; int bytesRead = -1; String message = ""; // keep listening to the InputStream while connected while(true) { try { // read from the input stream // bytesRead = mmInStream.read(buffer); // message = message+ new String(buffer, 0, bytesRead); // byte[] byteString = message.getBytes(); Log.i("info","pret a faire read"); bytesRead = mmInStream.read(buffer, 0, 1024); if (bytesRead != -1 && handlerCalling == 1) { mHandler.obtainMessage(MainActivityMemsBT.MESSAGE_READ, bytesRead, -1, buffer).sendToTarget(); } if (bytesRead !=-1 && handlerCalling == 2) { mHandler.obtainMessage(DemoAccelerometer.MESSAGE_READ, bytesRead, -1, buffer).sendToTarget(); } } catch (IOException e) { ConnectionLost(); break; } } } public void write(byte[] buffer) { try{ mmOutStream.write(buffer); // if (handlerCalling == 1) { // mHandler.obtainMessage(MainActivityMemsBT.MESSAGE_WRITE, -1, -1, buffer).sendToTarget(); Log.d(TAG,"envoi stream"); // mmOutStream.flush(); // } } catch (IOException e) { } } public void cancel() { try{ mmSocket.close(); } catch (IOException e) { } } } }
从Android 4.2升级到4.3后,当从我们的Nexus 4应用与外部蓝牙ECG(医疗设备)进行通信时,我们可以在6秒后确认蓝牙断开连接。这种情况特别发生在ECG测量中,其中包含大量入站数据(从ECG到Android应用),但没有出站数据。似乎不时会与某些入站和出站数据进行“正常”蓝牙通信。
6秒后,我们将看到JJM报告的相同adb日志消息
dm_pm_timer expires dm_pm_timer expires 0 proc dm_pm_timer expires btm_sec_disconnected - Clearing Pending flag
Android端的计时器到期会触发外部蓝牙ECG上的某些事件(关闭输出流,因为没有出站数据?),这反过来又发送了我们在输入流上收到的ECG特定命令,而在Android 4.2的Nexus 4上却从未收到过。
更改Android应用程序的实现以偶尔向ECG发送任意的“保持活动”命令即可解决此问题。计时器到期时间不再显示在adb日志中,ECG测量现在的行为与Android 4.2相同。
感谢JJM的提示。