Android 如果连接丢失,请重新连接到蓝牙设备
Android reconnect to bluetooth device if connection lost
我的 phone 正在连接到蓝牙设备并且工作正常。它连接并且连接保持。我可以改变方向,让我的应用程序在后台运行,我可以关闭应用程序,当我重新打开它时它会自动连接。但是从应用程序用户那里我得到一些报告说连接在一段时间后丢失(未检测到模式)。我试图重新创建这个但没有运气。所以为了避免这个问题,我想在连接丢失时自动重新连接到之前选择的设备。
我做了一些研究,这可以通过实施一个广播接收器来检测:android.bluetooth.device.action.ACL_DISCONNECTED
我的问题是:
- 我已经有一个在设备上触发的广播接收器
启动。我应该扩展此接收器以添加 ACL_DISCONNECTED 还是
添加单独的接收器?
- 我的 BluetoothService 已在我的主活动上初始化,但我需要从 intent 重新连接。怎么做。
感谢您的回答。
蓝牙服务代码:
public class BluetoothService
{
// Debugging
private static final String TAG = "BluetoothService";
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// Member fields
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private final Context mContext;
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_CONNECTING = 1; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 2; // now connected to a remote device
public BluetoothService(Context context, Handler handler)
{
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
mContext = context;
}
private synchronized void setState(int state)
{
mState = state;
mHandler.obtainMessage(MainActivity.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
public synchronized int getState()
{
return mState;
}
public synchronized void start()
{
if (mConnectThread != null)
{
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null)
{
mConnectedThread.cancel();
mConnectedThread = null;
}
}
public synchronized void connect(BluetoothDevice device)
{
if (mState == STATE_CONNECTING)
{
if (mConnectThread != null)
{
mConnectThread.cancel();
mConnectThread = null;
}
}
if (mConnectedThread != null)
{
mConnectedThread.cancel();
mConnectedThread = null;
}
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(STATE_CONNECTING);
}
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device, final String socketType)
{
if (mConnectThread != null)
{
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null)
{
mConnectedThread.cancel();
mConnectedThread = null;
}
mConnectedThread = new ConnectedThread(socket, socketType);
mConnectedThread.start();
Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(MainActivity.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
public synchronized void stop()
{
if (mConnectThread != null)
{
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null)
{
mConnectedThread.cancel();
mConnectedThread = null;
}
setState(STATE_NONE);
}
public void write(byte[] out)
{
ConnectedThread r;
synchronized (this)
{
if (mState != STATE_CONNECTED) return;
r = mConnectedThread;
}
r.write(out);
}
private void connectionFailed()
{
Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(MainActivity.TOAST, mContext.getResources().getString(R.string.cant_connect));
msg.setData(bundle);
mHandler.sendMessage(msg);
BluetoothService.this.start();
}
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;
mSocketType = "Secure";
// another option createInsecureRfcommSocketToServiceRecord
try
{
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
}
catch (IOException e)
{
Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
}
/*
Method m = null;
try {
m = mmDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
tmp = (BluetoothSocket) m.invoke(mmDevice, 1);
} catch (Exception e) {
e.printStackTrace();
}*/
mmSocket = tmp;
}
public void run()
{
Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
setName("ConnectThread" + mSocketType);
mAdapter.cancelDiscovery();
try
{
mmSocket.connect();
Log.i(TAG, "ConnectThread running");
}
catch (IOException e)
{
try
{
mmSocket.close();
}
catch (IOException e2)
{
Log.e(TAG, "unable to close() " + mSocketType + " socket during connection failure", e2);
}
connectionFailed();
return;
}
synchronized (BluetoothService.this)
{
mConnectThread = null;
}
connected(mmSocket, mmDevice, mSocketType);
}
public void cancel()
{
try
{
mmSocket.close();
}
catch (IOException e)
{
Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);
}
}
}
private class ConnectedThread extends Thread
{
private final BluetoothSocket mmSocket;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType)
{
mmSocket = socket;
OutputStream tmpOut = null;
try
{
tmpOut = socket.getOutputStream();
}
catch (IOException e)
{
Log.e(TAG, "temp sockets not created", e);
}
mmOutStream = tmpOut;
}
public void run()
{
}
public void write(byte[] buffer)
{
try
{
mmOutStream.write(buffer);
try
{
sleep(2000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
catch (IOException e)
{
Log.e(TAG, "Exception during write", e);
}
}
public void cancel()
{
try
{
mmSocket.close();
}
catch (IOException e)
{
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}
我分两个阶段解决了这个问题。
首先,我创建了一个新的广播接收器,因为我现有的接收器是针对 ACTION_BOOT_COMPLETED 的,必须在 android 清单中声明。我创建的那个必须是动态的,因为我需要 MainActivity 的一个实例:
if (bluetoothLostReceiver == null)
{
bluetoothLostReceiver = new BluetoothLostReceiver();
bluetoothLostReceiver.setMainActivity(this);
IntentFilter filter = new IntentFilter("android.bluetooth.device.action.ACL_DISCONNECTED");
registerReceiver(bluetoothLostReceiver, filter);
}
在我的接收器中,我尝试了一个新的打印机连接。我添加了一个额外的参数 tryBluetoothReconnect 这样如果我想关闭连接它就不会尝试重新连接。
public class BluetoothLostReceiver extends BroadcastReceiver {
MainActivity main = null;
public void setMainActivity(MainActivity main)
{
this.main = main;
}
@Override
public void onReceive(Context context, Intent intent) {
if(BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(intent.getAction()) && Global.tryBluetoothReconnect)
{
if(Global.PosPrinterDeviceName != null && !Global.PosPrinterDeviceName.equals(""))
main.connectPrinter(Global.PosPrinterDeviceName);
}else
{
Global.tryBluetoothReconnect = true;
}
}
}
我还升级了我的蓝牙服务,这样如果连接不成功(connectionFailed() 方法)它会再尝试 4 次:
if(tryCount >= 4)
{
tryCount = 0;
Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(MainActivity.TOAST, mContext.getResources().getString(R.string.cant_connect));
msg.setData(bundle);
mHandler.sendMessage(msg);
BluetoothService.this.start();
}
else
{
tryCount++;
connect(bluetoothDevice);
}
希望这对遇到同样问题的人有所帮助。
我的 phone 正在连接到蓝牙设备并且工作正常。它连接并且连接保持。我可以改变方向,让我的应用程序在后台运行,我可以关闭应用程序,当我重新打开它时它会自动连接。但是从应用程序用户那里我得到一些报告说连接在一段时间后丢失(未检测到模式)。我试图重新创建这个但没有运气。所以为了避免这个问题,我想在连接丢失时自动重新连接到之前选择的设备。
我做了一些研究,这可以通过实施一个广播接收器来检测:android.bluetooth.device.action.ACL_DISCONNECTED
我的问题是:
- 我已经有一个在设备上触发的广播接收器 启动。我应该扩展此接收器以添加 ACL_DISCONNECTED 还是 添加单独的接收器?
- 我的 BluetoothService 已在我的主活动上初始化,但我需要从 intent 重新连接。怎么做。
感谢您的回答。
蓝牙服务代码:
public class BluetoothService
{
// Debugging
private static final String TAG = "BluetoothService";
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// Member fields
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private final Context mContext;
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_CONNECTING = 1; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 2; // now connected to a remote device
public BluetoothService(Context context, Handler handler)
{
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
mContext = context;
}
private synchronized void setState(int state)
{
mState = state;
mHandler.obtainMessage(MainActivity.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
public synchronized int getState()
{
return mState;
}
public synchronized void start()
{
if (mConnectThread != null)
{
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null)
{
mConnectedThread.cancel();
mConnectedThread = null;
}
}
public synchronized void connect(BluetoothDevice device)
{
if (mState == STATE_CONNECTING)
{
if (mConnectThread != null)
{
mConnectThread.cancel();
mConnectThread = null;
}
}
if (mConnectedThread != null)
{
mConnectedThread.cancel();
mConnectedThread = null;
}
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(STATE_CONNECTING);
}
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device, final String socketType)
{
if (mConnectThread != null)
{
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null)
{
mConnectedThread.cancel();
mConnectedThread = null;
}
mConnectedThread = new ConnectedThread(socket, socketType);
mConnectedThread.start();
Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(MainActivity.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
public synchronized void stop()
{
if (mConnectThread != null)
{
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null)
{
mConnectedThread.cancel();
mConnectedThread = null;
}
setState(STATE_NONE);
}
public void write(byte[] out)
{
ConnectedThread r;
synchronized (this)
{
if (mState != STATE_CONNECTED) return;
r = mConnectedThread;
}
r.write(out);
}
private void connectionFailed()
{
Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(MainActivity.TOAST, mContext.getResources().getString(R.string.cant_connect));
msg.setData(bundle);
mHandler.sendMessage(msg);
BluetoothService.this.start();
}
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;
mSocketType = "Secure";
// another option createInsecureRfcommSocketToServiceRecord
try
{
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
}
catch (IOException e)
{
Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
}
/*
Method m = null;
try {
m = mmDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
tmp = (BluetoothSocket) m.invoke(mmDevice, 1);
} catch (Exception e) {
e.printStackTrace();
}*/
mmSocket = tmp;
}
public void run()
{
Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
setName("ConnectThread" + mSocketType);
mAdapter.cancelDiscovery();
try
{
mmSocket.connect();
Log.i(TAG, "ConnectThread running");
}
catch (IOException e)
{
try
{
mmSocket.close();
}
catch (IOException e2)
{
Log.e(TAG, "unable to close() " + mSocketType + " socket during connection failure", e2);
}
connectionFailed();
return;
}
synchronized (BluetoothService.this)
{
mConnectThread = null;
}
connected(mmSocket, mmDevice, mSocketType);
}
public void cancel()
{
try
{
mmSocket.close();
}
catch (IOException e)
{
Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);
}
}
}
private class ConnectedThread extends Thread
{
private final BluetoothSocket mmSocket;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType)
{
mmSocket = socket;
OutputStream tmpOut = null;
try
{
tmpOut = socket.getOutputStream();
}
catch (IOException e)
{
Log.e(TAG, "temp sockets not created", e);
}
mmOutStream = tmpOut;
}
public void run()
{
}
public void write(byte[] buffer)
{
try
{
mmOutStream.write(buffer);
try
{
sleep(2000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
catch (IOException e)
{
Log.e(TAG, "Exception during write", e);
}
}
public void cancel()
{
try
{
mmSocket.close();
}
catch (IOException e)
{
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}
我分两个阶段解决了这个问题。 首先,我创建了一个新的广播接收器,因为我现有的接收器是针对 ACTION_BOOT_COMPLETED 的,必须在 android 清单中声明。我创建的那个必须是动态的,因为我需要 MainActivity 的一个实例:
if (bluetoothLostReceiver == null)
{
bluetoothLostReceiver = new BluetoothLostReceiver();
bluetoothLostReceiver.setMainActivity(this);
IntentFilter filter = new IntentFilter("android.bluetooth.device.action.ACL_DISCONNECTED");
registerReceiver(bluetoothLostReceiver, filter);
}
在我的接收器中,我尝试了一个新的打印机连接。我添加了一个额外的参数 tryBluetoothReconnect 这样如果我想关闭连接它就不会尝试重新连接。
public class BluetoothLostReceiver extends BroadcastReceiver {
MainActivity main = null;
public void setMainActivity(MainActivity main)
{
this.main = main;
}
@Override
public void onReceive(Context context, Intent intent) {
if(BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(intent.getAction()) && Global.tryBluetoothReconnect)
{
if(Global.PosPrinterDeviceName != null && !Global.PosPrinterDeviceName.equals(""))
main.connectPrinter(Global.PosPrinterDeviceName);
}else
{
Global.tryBluetoothReconnect = true;
}
}
}
我还升级了我的蓝牙服务,这样如果连接不成功(connectionFailed() 方法)它会再尝试 4 次:
if(tryCount >= 4)
{
tryCount = 0;
Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(MainActivity.TOAST, mContext.getResources().getString(R.string.cant_connect));
msg.setData(bundle);
mHandler.sendMessage(msg);
BluetoothService.this.start();
}
else
{
tryCount++;
connect(bluetoothDevice);
}
希望这对遇到同样问题的人有所帮助。