如何保持蓝牙连接后台?

Posted

技术标签:

【中文标题】如何保持蓝牙连接后台?【英文标题】:How to keep Bluetooth connection background? 【发布时间】:2018-09-18 15:30:13 【问题描述】:

我在 android 应用中创建了一个蓝牙 Activity 类,它适用于所有蓝牙功能,例如:扫描、配对、连接、发送和接收数据。

真正的问题是 Activity 何时被销毁。蓝牙正在断开连接。

如何在整个应用程序中建立蓝牙连接。我想从其他活动向蓝牙发送数据。

帮我以简单的方式实现这个?

public class BTActivity extends AppCompatActivity 

ArrayList<BluetoothDevice> devices = new ArrayList<>();
BluetoothAdapter mBluetoothAdapter;
BluetoothDevice mBluetoothDevice;
ArrayAdapter<BluetoothDevice> arrayAdapter;

ConnectThread c;

private static final String TAG = "MY_BT";

ListView lvPaired;
Button BluetoothOnOff, ScanBt, pairedlist, sendButton, btDisconnect, incrementBtn, decrementBtn;
EditText input_text;
TextView ConnectedTo;

FragmentManager fm = getSupportFragmentManager();

UUID BHANU_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_bt);

    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    lvPaired = findViewById(R.id.btPairedLV);
    pairedlist = findViewById(R.id.btPaired);
    input_text = findViewById(R.id.user_input);
    sendButton = findViewById(R.id.btnSend);
    BluetoothOnOff = findViewById(R.id.offOn_bt);
    ScanBt = findViewById(R.id.scan_bt);
    ConnectedTo = findViewById(R.id.current_connected_bluetooth);
    btDisconnect = findViewById(R.id.bt_disconnect);
    incrementBtn = findViewById(R.id.incrementBtn);
    decrementBtn = findViewById(R.id.decrementBtn);

    onClickListener();
    pairedList();

    IntentFilter filter = new IntentFilter();
    filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
    filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
    registerReceiver(mReceiver, filter);


public void onClickListener()

    pairedlist.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            if (arrayAdapter != null)
                arrayAdapter.clear();
            
            pairedList();
        
    );

    lvPaired.setOnItemClickListener(new AdapterView.OnItemClickListener() 
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) 
            BluetoothDevice device = (BluetoothDevice) parent.getItemAtPosition(position);
            c = new ConnectThread(device, true);
            c.start();
        
    );
    sendButton.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            String text = input_text.getText().toString();
            c.sendData(text);
            input_text.setText("");

        
    );
    BluetoothOnOff.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            if (!mBluetoothAdapter.isEnabled())
                mBluetoothAdapter.enable();
                BluetoothOnOff.setText("ON");
            else 
                mBluetoothAdapter.disable();
                BluetoothOnOff.setText("OFF");
            
        
    );
    ScanBt.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            ScanFragment scanFragment = new ScanFragment();
            scanFragment.show(fm,"ScanBT");
            //ScanFragment scanFragment = new ScanFragment();
            //scanFragment.show(fm,"Scan Fragment");
        
    );
    btDisconnect.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            c.cancel();
        
    );

    incrementBtn.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            c.sendData("a");
        
    );
    decrementBtn.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            c.sendData("b");
        
    );




public void toast(String message) 
    Toast.makeText(this, message, Toast.LENGTH_SHORT).show();


@Override
protected void onDestroy() 
    unregisterReceiver(mReceiver);
    super.onDestroy();


public void pairedList() 
    //arrayAdapter.clear();
    devices.addAll(mBluetoothAdapter.getBondedDevices());
    arrayAdapter = new ArrayAdapter<BluetoothDevice>(this, android.R.layout.simple_list_item_1,android.R.id.text1, devices);
    lvPaired.setAdapter(arrayAdapter);
    arrayAdapter.notifyDataSetChanged();



BroadcastReceiver mReceiver = new BroadcastReceiver() 
    @Override
    public void onReceive(Context context, Intent intent) 
        String action = intent.getAction();
        if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) 
            toast("connected");
            BluetoothDevice device = intent
                    .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            ConnectedTo.setText(device.getName());
            btDisconnect.setVisibility(View.VISIBLE);
            //getActionBar().setSubtitle(device.getName());
            Log.d("BT", "connected to");
         else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) 
            toast("disconnected");
            ConnectedTo.setText("None");
            btDisconnect.setVisibility(View.INVISIBLE);
           // getActionBar().setSubtitle("");
            Log.d("BT", "disconnected");
        

    
;


public class ConnectThread extends Thread 
    BluetoothDevice cDevice;
    BluetoothSocket socket;
    ConnectedThread ct;

    ConnectThread(BluetoothDevice device, boolean insecureConnection) 
        cDevice = device;
        try 
            if (insecureConnection) 
                socket = device.createInsecureRfcommSocketToServiceRecord(BHANU_UUID);
             else 
                socket = device.createRfcommSocketToServiceRecord(BHANU_UUID);
            
         catch (IOException e) 
            e.getMessage();
        
    

    public void run() 
        mBluetoothAdapter.cancelDiscovery();

        try 
            Log.d("BT", "Socket ready to connect");
            socket.connect();
            Log.d("BT", "Socket connected");
            // out = socket.getOutputStream();
            // input = new BufferedReader(new InputStreamReader(socket.getInputStream()));


         catch (final IOException e) 
            e.getMessage();
        

        ct = new ConnectedThread(socket);

        //ct.write("Q-smart".getBytes());
            /*try 
                socket.close();
             catch (final IOException closeException) 
                closeException.getMessage();
            */
    
    private void sendData(String message)
        Log.d(TAG,message);
        if (socket != null)
            ct.write(message.getBytes());
        else 
            toast("Please connect to bluetooth first");
        
    

    public void cancel() 
        try 
            socket.close();
         catch (IOException e) 
            e.printStackTrace();
        
    


private class ConnectedThread extends Thread 
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;
    private byte[] mmBuffer; // mmBuffer store for the stream

    public ConnectedThread(BluetoothSocket socket) 
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        // Get the input and output streams; using temp objects because
        // member streams are final.
        try 
            tmpIn = socket.getInputStream();
         catch (IOException e) 
            Log.e(TAG, "Error occurred when creating input stream", e);
        
        try 
            tmpOut = socket.getOutputStream();
         catch (IOException e) 
            Log.e(TAG, "Error occurred when creating output stream", e);
        

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    

    public void run() 
        mmBuffer = new byte[1024];
        int numBytes; // bytes returned from read()

        // Keep listening to the InputStream until an exception occurs.
        while (true) 
            try 
                // Read from the InputStream.
                numBytes = mmInStream.read(mmBuffer);
                // Send the obtained bytes to the UI activity.
               /* Message readMsg = mHandler.obtainMessage(
                        MessageConstants.MESSAGE_READ, numBytes, -1,
                        mmBuffer);
                readMsg.sendToTarget();*/
             catch (IOException e) 
                Log.d(TAG, "Input stream was disconnected", e);
                break;
            
        
    

    // Call this from the main activity to send data to the remote device.
    public void write(byte[] bytes) 
        try 
            mmOutStream.write(bytes);

            // Share the sent message with the UI activity.
           /* Message writtenMsg = mHandler.obtainMessage(
                    MessageConstants.MESSAGE_WRITE, -1, -1, mmBuffer);
            writtenMsg.sendToTarget();*/
         catch (IOException e) 
            Log.e(TAG, "Error occurred when sending data", e);

            // Send a failure message back to the activity.
           /* Message writeErrorMsg =
                    mHandler.obtainMessage(MessageConstants.MESSAGE_TOAST);
            Bundle bundle = new Bundle();
            bundle.putString("toast",
                    "Couldn't send data to the other device");
            writeErrorMsg.setData(bundle);
            mHandler.sendMessage(writeErrorMsg);*/
        
    




【问题讨论】:

【参考方案1】:

是的,我找到了在 Android 中运行蓝牙背景的可行解决方案。 下面是我在我的 android 应用中使用的代码。

public class BluetoothServices extends Service 

    private BluetoothAdapter mBluetoothAdapter;
    public static final String B_DEVICE = "MY DEVICE";
    public static final String B_UUID = "00001101-0000-1000-8000-00805f9b34fb";
    // 00000000-0000-1000-8000-00805f9b34fb

    public static final int STATE_NONE = 0;
    public static final int STATE_LISTEN = 1;
    public static final int STATE_CONNECTING = 2;
    public static final int STATE_CONNECTED = 3;

    private ConnectBtThread mConnectThread;
    private static ConnectedBtThread mConnectedThread;

    private static Handler mHandler = null;
    public static int mState = STATE_NONE;
    public static String deviceName;
    public static BluetoothDevice sDevice = null;
    public Vector<Byte> packData = new Vector<>(2048);

    //IBinder mIBinder = new LocalBinder();


    @Nullable
    @Override
    public IBinder onBind(Intent intent) 
        //mHandler = getApplication().getHandler();
        return mBinder;
    
    public void toast(String mess)
        Toast.makeText(this,mess,Toast.LENGTH_SHORT).show();
    
    private final IBinder mBinder = new LocalBinder();

    public class LocalBinder extends Binder 
        BluetoothServices getService() 
            // Return this instance of LocalService so clients can call public methods
            return BluetoothServices.this;
        
    

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 

        String deviceg = intent.getStringExtra("bluetooth_device");


        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

                connectToDevice(deviceg);

        return START_STICKY;
    
    private synchronized void connectToDevice(String macAddress)
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(macAddress);
        if (mState == STATE_CONNECTING)
            if (mConnectThread != null)
                mConnectThread.cancel();
                mConnectThread = null;
            
        
        if (mConnectedThread != null)
            mConnectedThread.cancel();
            mConnectedThread = null;
        
        mConnectThread = new ConnectBtThread(device);
        toast("connecting");
        mConnectThread.start();
        setState(STATE_CONNECTING);
    
    private void setState(int state)
        mState = state;
        if (mHandler != null)
           // mHandler.obtainMessage();
        
    
    public synchronized void stop()
        setState(STATE_NONE);
        if (mConnectThread != null)
            mConnectThread.cancel();
            mConnectThread = null;
        
        if (mConnectedThread != null)
            mConnectedThread.cancel();
            mConnectedThread = null;
        
        if (mBluetoothAdapter != null)
            mBluetoothAdapter.cancelDiscovery();
        

        stopSelf();
    

    public void sendData(String message)
        if (mConnectedThread!= null)
            mConnectedThread.write(message.getBytes());
            toast("sent data");
        else 
            Toast.makeText(BluetoothServices.this,"Failed to send data",Toast.LENGTH_SHORT).show();
        
    

    @Override
    public boolean stopService(Intent name) 
        setState(STATE_NONE);

        if (mConnectThread != null)
            mConnectThread.cancel();
            mConnectThread = null;
        

        if (mConnectedThread != null)
            mConnectedThread.cancel();
            mConnectedThread = null;
        

        mBluetoothAdapter.cancelDiscovery();
        return super.stopService(name);
    

    /*private synchronized void connected(BluetoothSocket mmSocket)

        if (mConnectThread != null)
            mConnectThread.cancel();
            mConnectThread = null;
        
        if (mConnectedThread != null)
            mConnectedThread.cancel();
            mConnectedThread = null;
        

        mConnectedThread = new ConnectedBtThread(mmSocket);
        mConnectedThread.start();


        setState(STATE_CONNECTED);
    */

    private class ConnectBtThread extends Thread
        private final BluetoothSocket mSocket;
        private final BluetoothDevice mDevice;

        public ConnectBtThread(BluetoothDevice device)
            mDevice = device;
            BluetoothSocket socket = null;
            try 
                socket = device.createInsecureRfcommSocketToServiceRecord(UUID.fromString(B_UUID));
             catch (IOException e) 
                e.printStackTrace();
            
            mSocket = socket;

        

        @Override
        public void run() 
            mBluetoothAdapter.cancelDiscovery();

            try 
                mSocket.connect();
                Log.d("service","connect thread run method (connected)");
                SharedPreferences pre = getSharedPreferences("BT_NAME",0);
                pre.edit().putString("bluetooth_connected",mDevice.getName()).apply();

             catch (IOException e) 

                try 
                    mSocket.close();
                    Log.d("service","connect thread run method ( close function)");
                 catch (IOException e1) 
                    e1.printStackTrace();
                
                e.printStackTrace();
            
            //connected(mSocket);
            mConnectedThread = new ConnectedBtThread(mSocket);
            mConnectedThread.start();
        

        public void cancel()

            try 
                mSocket.close();
                Log.d("service","connect thread cancel method");
             catch (IOException e) 
                e.printStackTrace();
            
        
    

    private class ConnectedBtThread extends Thread
        private final BluetoothSocket cSocket;
        private final InputStream inS;
        private final OutputStream outS;

        private byte[] buffer;

        public ConnectedBtThread(BluetoothSocket socket)
            cSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            try 
                tmpIn = socket.getInputStream();

             catch (IOException e) 
                e.printStackTrace();
            

            try 
                tmpOut = socket.getOutputStream();
             catch (IOException e) 
                e.printStackTrace();
            

            inS = tmpIn;
            outS = tmpOut;
        

        @Override
        public void run() 
            buffer = new byte[1024];
            int mByte;
            try 
                mByte= inS.read(buffer);
             catch (IOException e) 
                e.printStackTrace();
            
            Log.d("service","connected thread run method");

        


        public void write(byte[] buff)
            try 
                outS.write(buff);
             catch (IOException e) 
                e.printStackTrace();
            
        

        private void cancel()
            try 
                cSocket.close();
                Log.d("service","connected thread cancel method");
             catch (IOException e) 
                e.printStackTrace();
            
        
    

    @Override
    public void onDestroy() 
        this.stop();
        super.onDestroy();
    

【讨论】:

Android 不会在一段时间(10 小时左右)后终止您的服务?我有这个问题,谢谢。 你如何从我的活动中访问它? 使用 Ibinder。使用服务连接将此服务连接到您的活动

以上是关于如何保持蓝牙连接后台?的主要内容,如果未能解决你的问题,请参考以下文章

iOS - 当应用程序在后台时取消蓝牙连接

iOS蓝牙后台模式

当应用程序未运行(终止/终止)时,如何保持核心位置和核心蓝牙运行?

移动应用程序可以连接到 BLE 设备并在后台保持连接数小时吗?

蓝牙 LE 在暂停时断开连接

如何在后台保持 iphone ios websocket 连接处于活动状态?