如果连接丢失,Android将重新连接到蓝牙设备

时间:2022-12-15 18:57:02

My phone is connecting to a bluetooth device and it works normally. It connect and the connection holds. I can change orientation, have my app in the background, I can close app and when I turn it back on it will automatically connect. But from app users I get some reports that the connection is lost after a period of time(no pattern detected). I have tried to recreate this but with no luck. So to avoid this problem I want to implement an automatic reconnect to the previously selected device if connection is lost.

我的手机正在连接蓝牙设备,工作正常。它连接并且连接成立。我可以更改方向,在后台安装我的应用程序,我可以关闭应用程序,当我将其重新打开时,它将自动连接。但是从应用程序用户那里我得到一些报告说连接在一段时间后丢失(没有检测到模式)。我试图重新创造这个,但没有运气。因此,为了避免此问题,我想在连接丢失时实现自动重新连接到之前选择的设备。

I did some reasearch that this could be done by implementing a broadcast reciever that would detect: android.bluetooth.device.action.ACL_DISCONNECTED

我做了一些研究,可以通过实现一个可以检测到的广播接收器来完成:android.bluetooth.device.action.ACL_DISCONNECTED

What my questions are:

我的问题是:

  • I already have a broadcast reciever that is triggered on device bootup. Should I extend this reciever to add the ACL_DISCONNECTED or add a separate reciever?
  • 我已经有一个在设备启动时触发的广播接收器。我是否应该扩展此接收器以添加ACL_DISCONNECTED或添加单独的接收器?

  • My BluetoothService is initialised on my mainactivity, but I will need to reconnect from the intent. How to do that.
  • 我的BluetoothService初始化我的mainactivity,但我需要重新连接intent。怎么做。

Thanks for your answer.

感谢您的回答。

BluetoothServis code:

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);
        }
    }
}

}

1 个解决方案

#1


I solved this in 2 stages. First I created a new broadcast reciever because my existing one was for ACTION_BOOT_COMPLETED and had to be declared in the android manifest. The one I created had to be dynamic because I needed an instance of MainActivity:

我分两个阶段解决了这个问题。首先我创建了一个新的广播接收器,因为我现有的广播接收器是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);
        }

And in my reciever I tried a new connect to the printer. I added an additional paramenter tryBluetoothReconnect so that if I wanted to close the connection it wouldn't try to reconnect.

在我的收件人中,我尝试了一种新的打印机连接。我添加了一个额外的参数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;
        }
    }
}

I also upgraded my Bluetooth service so that if connection was not successful (connectionFailed() method) it would try 4 more times:

我还升级了我的蓝牙服务,这样如果连接不成功(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);
    }

Hope this helps anyone with the same problem.

希望这可以帮助任何有同样问题的人。

#1


I solved this in 2 stages. First I created a new broadcast reciever because my existing one was for ACTION_BOOT_COMPLETED and had to be declared in the android manifest. The one I created had to be dynamic because I needed an instance of MainActivity:

我分两个阶段解决了这个问题。首先我创建了一个新的广播接收器,因为我现有的广播接收器是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);
        }

And in my reciever I tried a new connect to the printer. I added an additional paramenter tryBluetoothReconnect so that if I wanted to close the connection it wouldn't try to reconnect.

在我的收件人中,我尝试了一种新的打印机连接。我添加了一个额外的参数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;
        }
    }
}

I also upgraded my Bluetooth service so that if connection was not successful (connectionFailed() method) it would try 4 more times:

我还升级了我的蓝牙服务,这样如果连接不成功(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);
    }

Hope this helps anyone with the same problem.

希望这可以帮助任何有同样问题的人。