我正在开发一个项目,该项目使用在4.1.2上运行的安卓平板电脑(iball 3G 7271),由MTK处理器和RN42蓝牙(PCB上的芯片)组成。这两个模块与每个模块通信其他通过蓝牙传输数据。
我正面临着一些问题。在某些情况下,我反复得到例外情况,说明没有创建连接(失败或中止)'。我已经找到了如下所述的实例:
我从BlueTerm应用程序(来自playstore)复制了相关代码并制作了一个示例应用程序来测试BT连接.Blueterm是一个用于测试设备和RN42之间蓝牙连接的应用程序。
1)我将应用程序连接/断开连接到RN42,发现它一直在工作。正在进行正确的连接和断开连接。 2)I模拟电源故障(仅通过关闭RN42模块),然后断开&重新连接app和RN42之间的BT连接&发现平板电脑与RN42重新连接没有太多问题。
3)重新安装应用程序与BT连接到RN42之间的链接
测试用例1:在重新安装之前,应用程序已与RN42断开连接;结果 - 重新安装后BT重新连接到重新安装的应用程序中的RN42工作正常。
测试用例2:在重新安装之前,应用程序处于连接状态RN42;结果 - 重新安装后BT重新连接到RN42没有发生。 我追溯到测试用例2的异常是:
W/System.err(4603): java.io.IOException: [JSR82] connect: Connection is not created (failed or aborted).
W/System.err(4603): at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:395)
这是我几天前一次又一次地得到的例外。所以现在我知道什么时候会抛出这个异常。
注意:对于'测试用例2' ,这里甚至卸载并重新安装应用程序,然后尝试将应用程序连接到RN42不起作用。我们需要重新启动平板电脑,使应用程序再次连接到BT。此外,我甚至尝试连接真正的BlueTerm应用程序(在测试用例2),但它也没有连接。然后我尝试关闭和打开平板电脑的BT.I观察到通过关闭然后打开BT然后尝试在平板电脑之间建立BT连接现在,我没有从RN42到平板电脑获得任何输入信号,但只能将数据从平板电脑发送到RN42。
在三星S2 / grand / nexus设备上进行测试: 对于上述测试用例2,在重新安装后,即使在重新安装之前已经/未通过BT连接到RN42,应用程序也会在重新安装后连接到BT。
以下是我的应用程序代码和日志猫例外:
BlueTerm.java
@SuppressLint("HandlerLeak")
public class BlueTerm extends Activity {
BluetoothSocket Socket;
OutputStream DataOut;
InputStream DataIn;
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
private static TextView mTitle;
// Name of the connected device
private String mConnectedDeviceName = null;
/**
* Set to true to add debugging code and logging.
*/
public static final boolean DEBUG = true;
/**
* Set to true to log each character received from the remote process to the
* android log, which makes it easier to debug some kinds of problems with
* emulating escape sequences and control codes.
*/
public static final boolean LOG_CHARACTERS_FLAG = DEBUG && false;
/**
* Set to true to log unknown escape sequences.
*/
public static final boolean LOG_UNKNOWN_ESCAPE_SEQUENCES = DEBUG && false;
/**
* The tag we use when logging, so that our messages can be distinguished
* from other messages in the log. Public because it's used by several
* classes.
*/
public static final String LOG_TAG = "BlueTerm";
// Message types sent from the BluetoothReadService Handler
public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_READ = 2;
public static final int MESSAGE_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;
// Key names received from the BluetoothChatService Handler
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";
private BluetoothAdapter mBluetoothAdapter = null;
private static BluetoothSerialService mSerialService = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (DEBUG)
Log.e(LOG_TAG, "+++ ON CREATE +++");
setContentView(R.layout.main);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mSerialService = new BluetoothSerialService(this, mHandlerBT);
Button buzzerOn = (Button) findViewById(R.id.button1);
buzzerOn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.v("BlueTerm","Buzzer button clicked");
//send("37".getBytes());
send(bigIntToByteArray(37));
}
});
Button buzzerOff = (Button) findViewById(R.id.button2);
buzzerOff.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.v("BlueTerm","Buzzer button clicked");
//send("37".getBytes());
send(bigIntToByteArray(30));
}
});
Button recon = (Button) findViewById(R.id.button3);
recon.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.v("BlueTerm","recon button clicked");
BluetoothAdapter iballAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice RN42_Device = iballAdapter.getRemoteDevice("00:06:66:49:57:5F");
try {
Socket = RN42_Device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
DataOut = Socket.getOutputStream();
DataIn = Socket.getInputStream();
} catch (Exception e1) {
e1.printStackTrace();
}
if (DataIn != null) {
Log.d("AppFunctions","DataIn is not null,so making it NULL");
try {DataIn.close();} catch (Exception e) {}
DataIn = null;
}
Log.i("AppFunctions", "DataOut -" + DataOut);
if (DataOut != null) {
Log.d("AppFunctions","DataOut is not null,so making it NULL");
try {DataOut.close();} catch (Exception e) {}
DataOut = null;
}
Log.i("AppFunctions", "Socket -" + Socket);
if (Socket != null) {
Log.d("AppFunctions","Socket is not null,so making it NULL");
try {Socket.close();} catch (Exception e) {}
Socket = null;
}
try {
Socket = RN42_Device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
Socket.connect();
} catch (Exception e) {
e.printStackTrace();
}
if (mSerialService != null)
mSerialService.stop();
mSerialService.start();
}
});
if (DEBUG)
Log.e(LOG_TAG, "+++ DONE IN ON CREATE +++");
}
@Override
public void onStart() {
super.onStart();
if (DEBUG)
Log.e(LOG_TAG, "++ ON START ++");
mEnablingBT = false;
}
@Override
public synchronized void onResume() {
super.onResume();
if (DEBUG) {
Log.e(LOG_TAG, "+ ON RESUME +");
}
if (mSerialService != null) {
Log.v("BlueTerm","mSerialService is NOT null");
// Only if the state is STATE_NONE, do we know that we haven't started already
if (mSerialService.getState() == BluetoothSerialService.STATE_NONE) {
// Start the Bluetooth chat services
Log.v("BlueTerm","starting BT chat service");
mSerialService.start();
}
}
}
}
@Override
public synchronized void onPause() {
super.onPause();
if (DEBUG)
Log.e(LOG_TAG, "- ON PAUSE -");
}
@Override
public void onStop() {
super.onStop();
if(DEBUG)
Log.e(LOG_TAG, "-- ON STOP --");
}
@Override
public void onDestroy() {
super.onDestroy();
if (DEBUG)
Log.e(LOG_TAG, "--- ON DESTROY ---");
if (mSerialService != null)
mSerialService.stop();
}
public int getConnectionState() {
return mSerialService.getState();
}
public void send(byte[] out) {
mSerialService.write( out );
}
// The Handler that gets information back from the BluetoothService
private final Handler mHandlerBT = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_STATE_CHANGE:
if(DEBUG) Log.i(LOG_TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
switch (msg.arg1) {
case BluetoothSerialService.STATE_CONNECTED:
break;
case BluetoothSerialService.STATE_CONNECTING:
break;
case BluetoothSerialService.STATE_LISTEN:
case BluetoothSerialService.STATE_NONE:
Log.d("BlueTerm","inside STATE_NONE in handler");
break;
}
break;
case MESSAGE_WRITE:
if (mLocalEcho) {
byte[] writeBuf = (byte[]) msg.obj;
}
break;
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
Log.d("incoming writebytes",""+readBuf.toString());
break;
case MESSAGE_DEVICE_NAME:
// save the connected device's name
mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
Toast.makeText(getApplicationContext(), "Connected to "
+ mConnectedDeviceName, Toast.LENGTH_SHORT).show();
break;
case MESSAGE_TOAST:
Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),
Toast.LENGTH_SHORT).show();
break;
}
}
};
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(DEBUG) Log.d(LOG_TAG, "onActivityResult " + resultCode);
switch (requestCode) {
case REQUEST_CONNECT_DEVICE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
// Get the device MAC address
String address = "00:06:66:49:57:5F";
// Get the BLuetoothDevice object
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
// Attempt to connect to the device
mSerialService.connect(device);
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
Log.d(LOG_TAG, "BT not enabled");
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.option_menu, menu);
mMenuItemConnect = menu.getItem(0);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.connect:
if (getConnectionState() == BluetoothSerialService.STATE_NONE) {
String address = "00:06:66:49:57:5F";
// Get the BLuetoothDevice object
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
Log.d("BlueTerm","device: " + device);
// Attempt to connect to the device
mSerialService.connect(device);
}
else
if (getConnectionState() == BluetoothSerialService.STATE_CONNECTED) {
mSerialService.stop();
mSerialService.start();
}
return true;
case R.id.preferences:
//doPreferences();
return true;
case R.id.menu_special_keys:
//doDocumentKeys();
return true;
}
return false;
}
private byte[] bigIntToByteArray( final int i ) {
BigInteger bigInt = BigInteger.valueOf(i);
return bigInt.toByteArray();
}
}
BluetoothService:
/**
* This class does all the work for setting up and managing Bluetooth
* connections with other devices. It has a thread that listens for
* incoming connections, a thread for connecting with a device, and a
* thread for performing data transmissions when connected.
*/
public class BluetoothSerialService {
// Debugging
private static final String TAG = "BluetoothReadService";
private static final boolean D = true;
private static final UUID SerialPortServiceClass_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// Member fields
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
// Constants that indicate the current connection state
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_LISTEN = 1; // now listening for incoming connections
public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 3; // now connected to a remote device
/**
* Constructor. Prepares a new BluetoothChat session.
* @param context The UI Activity Context
* @param handler A Handler to send messages back to the UI Activity
*/
public BluetoothSerialService(Context context, Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
// mEmulatorView = emulatorView;
}
/**
* Set the current state of the chat connection
* @param state An integer defining the current connection state
*/
private synchronized void setState(int state) {
if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
mState = state;
Log.d("BluetoothSerialService","state : " + state);
// Give the new state to the Handler so the UI Activity can update
mHandler.obtainMessage(BlueTerm.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
/**
* Return the current connection state. */
public synchronized int getState() {
return mState;
}
/**
* Start the chat service. Specifically start AcceptThread to begin a
* session in listening (server) mode. Called by the Activity onResume() */
public synchronized void start() {
if (D) Log.d(TAG, "start");
// Cancel any thread attempting to make a connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
setState(STATE_NONE);
}
/**
* Start the ConnectThread to initiate a connection to a remote device.
* @param device The BluetoothDevice to connect
*/
public synchronized void connect(BluetoothDevice device) {
if (D) Log.d(TAG, "connect to: " + device);
// Cancel any thread attempting to make a connection
if (mState == STATE_CONNECTING) {
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 connect with the given device
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(STATE_CONNECTING);
}
/**
* Start the ConnectedThread to begin managing a Bluetooth connection
* @param socket The BluetoothSocket on which the connection was made
* @param device The BluetoothDevice that has been connected
*/
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
if (D) Log.d(TAG, "connected");
// Cancel the thread that 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 transmissions
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
// Send the name of the connected device back to the UI Activity
Message msg = mHandler.obtainMessage(BlueTerm.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(BlueTerm.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
/**
* Stop all threads
*/
public synchronized void stop() {
if (D) Log.d(TAG, "stop");
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
setState(STATE_NONE);
}
/**
* Write to the ConnectedThread in an unsynchronized manner
* @param out The bytes to write
* @see ConnectedThread#write(byte[])
*/
public void write(byte[] out) {
Log.e("BluetoothSerialService","Inside write fn" + " :" + out.toString());
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mState != STATE_CONNECTED) return;
r = mConnectedThread;
}
// Perform the write unsynchronized
r.write(out);
}
/**
* Indicate that the connection attempt failed and notify the UI Activity.
*/
private void connectionFailed() {
setState(STATE_NONE);
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(BlueTerm.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BlueTerm.TOAST, "Unable to connect device");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
/**
* Indicate that the connection was lost and notify the UI Activity.
*/
private void connectionLost() {
setState(STATE_NONE);
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(BlueTerm.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BlueTerm.TOAST, "Device connection was lost");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
/**
* This thread runs while attempting to make 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;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
tmp = device.createRfcommSocketToServiceRecord(SerialPortServiceClass_UUID);
} catch (IOException e) {
Log.e(TAG, "create() failed", e);
}
mmSocket = tmp;
}
public void run() {
Log.e(TAG, "BEGIN mConnectThread");
setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
connectionFailed();
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() socket during connection failure", e2);
}
// Start the service over to restart listening mode
//BluetoothSerialService.this.start();
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothSerialService.this) {
mConnectThread = null;
}
// Start the connected thread
connected(mmSocket, mmDevice);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
/**
* This thread runs during a connection with a remote device.
* It handles all incoming and outgoing transmissions.
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.e(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.e(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
Log.e(TAG, "Entering while");
while (true) {
Log.e(TAG, "Inside while");
try {
// Read from the InputStream
bytes = 0;
Log.d("incoming bytes",""+bytes);
Log.e("BT","Inputstream :" + mmInStream);
//bytes = mmInStream.read(buffer);
bytes = mmInStream.read();
Log.d("incoming bytes",""+bytes);
//mEmulatorView.write(buffer, bytes);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(BlueTerm.MESSAGE_READ, bytes, -1, buffer).sendToTarget();
String a = buffer.toString();
a = "";
} catch (Exception e) {
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
bytes = 0;
}
//Log.e(TAG, "Outside while");
}
/**
* Write to the connected OutStream.
* @param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
Log.d("writing to outStream byte :", buffer.toString());
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
//mHandler.obtainMessage(BlueTerm.MESSAGE_WRITE, buffer.length, -1, buffer).sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (Exception e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}
Logcat错误:
W / System.err(4603):java.io.IOException:[JSR82] connect:未创建连接(失败或中止)。 W / System.err(4603):在android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:395)
我怀疑这个错误可能会被抛出,因为应用程序无法访问活动的BT端口,在上面提到的测试用例中。原因是因为我读了这个网站:https://code.google.com/p/android/issues/detail?id=5427(参见答案# 19 dknop) 我发现在我测试的三星s2 / grand / nexus设备上没有出现这个问题。我的错误也可能是由于MTK处理器/它的BT固件/ iball定制的android问题。(http://redacacia.me/2012/07/17/overcoming-android-bluetooth-blues-with-reflection-method/)
有没有人遇到过类似的问题?任何帮助将不胜感激。非常感谢!
答案 0 :(得分:5)
我已经在几十种不同的平板电脑上测试了蓝牙连接,我发现了一些非常不稳定的行为。我的应用程序总是在循环中调用createRfcommSocketToServiceRecord(...)
,因为有时它会因为没有明显的原因而失败,只会在以后的尝试中成功。 API并不能让您区分瞬态和永久性故障。某些平板电脑会在错误消息的文本中为您提供线索,但其他平板电脑不会。
我通常尝试以100毫秒的间隔连接100次,然后停下来询问用户他们尝试连接的设备是否已打开且在范围内。在我测试的一个特定的平板电脑型号上,连接失败超过300次并不罕见......然后突然之间就会发生任何错误。
答案 1 :(得分:4)
我已经使用这段代码使我与蓝牙设备(即蓝牙打印机)的连接稳定。现在它连接了9.9次。如果仍然发生了一些错误我以编程方式重置我的蓝牙再次调用这段代码然后它连接10次中的10次。
public boolean connectToPrinter(String printerName) throws IOException
{
BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
BluetoothDevice device = getPrinterByName(printerName);
if (bluetoothSocket != null)
{
bluetoothSocket.close();
}
try {
Method m=device.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
bluetoothSocket= (BluetoothSocket) m.invoke(device, 1);
} catch (Exception e) {
e.printStackTrace();
}
if (bluetoothSocket == null)
return false;
bluetoothSocket.connect();
return true;
}
这是getPrinterByName()的代码:
private BluetoothDevice getPrinterByName(String printerName)
{
Set<BluetoothDevice> pairedDevices = BluetoothAdapter.getDefaultAdapter().getBondedDevices();
for (BluetoothDevice device : pairedDevices)
{
Log.e("","device name: "+device.getName());
if (device.getName() == null)
continue;
if (device.getName().contains(printerName))
{
remoteDevice = device;
// pairPrinter(printerName);
return remoteDevice;
}
}
return null;
}
bluetoothSocket是BluetoothSocket类的对象。并且不要忘记在线程中运行此代码,否则这将阻止您的主线程。 : - )
答案 2 :(得分:1)
嗨朋友只需用反射代码替换代码连接到bluetoothsocket 建立联系.....
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);
}
答案 3 :(得分:0)
引用:我观察到通过关闭然后打开BT然后尝试建立平板电脑和RN42之间的BT连接正在发生。但是现在,我没有从RN42到平板电脑获得任何输入信号,但是能够只需将数据从平板电脑发送到RN42。
那么,在重新安装应用程序之前,它可以从rn42接收输入信号吗?