Android多Activity共享蓝牙通信后台线程实现方案咨询
可行实现方案:基于Bound Service + HandlerThread的蓝牙通信架构
核心思路
把蓝牙连接、消息收发、延迟循环逻辑全部托管给后台Bound Service,两个Activity通过绑定Service实现与后台通信线程的交互。这种方案能避开Activity生命周期波动带来的连接中断、消息丢失问题,同时保证所有蓝牙操作都在后台线程执行,不阻塞UI。
具体实现步骤
1. 创建蓝牙通信Service
Service是Android系统托管的后台组件,生命周期独立于Activity,适合长期持有蓝牙连接并处理循环任务。
- 内部用
HandlerThread创建专属后台线程,承载蓝牙读写、延迟循环逻辑 - 通过
Messenger实现与Activity的消息传递(同一进程下高效且无需复杂IPC) - 统一管理蓝牙Socket、输入输出流,在Service生命周期内维护连接
public class BluetoothCommService extends Service { private HandlerThread mCommThread; private Handler mServiceHandler; private Messenger mMessenger; private BluetoothSocket mSocket; private InputStream mInStream; private OutputStream mOutStream; // 消息类型常量 public static final int MSG_SEND_DATA = 1; public static final int MSG_REGISTER_CLIENT = 2; public static final int MSG_UNREGISTER_CLIENT = 3; public static final int MSG_RECEIVE_DATA = 4; // 保存已注册的Activity客户端,用于回传数据 private final ArrayList<Messenger> mClients = new ArrayList<>(); @Override public void onCreate() { super.onCreate(); // 初始化后台通信线程 mCommThread = new HandlerThread("BluetoothWorker"); mCommThread.start(); mServiceHandler = new Handler(mCommThread.getLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SEND_DATA: // 接收Activity发送的指令,写入蓝牙输出流 sendToArduino((String) msg.obj); break; case MSG_REGISTER_CLIENT: // 注册Activity的Messenger,用于回传数据 mClients.add(msg.replyTo); break; case MSG_UNREGISTER_CLIENT: mClients.remove(msg.replyTo); break; } } }; mMessenger = new Messenger(mServiceHandler); // 后台初始化蓝牙连接 mServiceHandler.post(this::initBluetoothConnection); // 启动循环读取Arduino数据的任务 startReadLoop(); } private void initBluetoothConnection() { try { // 替换为你的蓝牙设备配对逻辑,这里假设已获取目标BluetoothDevice BluetoothDevice device = ...; mSocket = device.createRfcommSocketToServiceRecord( UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") ); mSocket.connect(); mInStream = mSocket.getInputStream(); mOutStream = mSocket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); // 可添加重连逻辑,比如延迟3秒后重试 mServiceHandler.postDelayed(this::initBluetoothConnection, 3000); } } private void startReadLoop() { Runnable readTask = new Runnable() { @Override public void run() { if (mInStream == null) { mServiceHandler.postDelayed(this, 100); return; } byte[] buffer = new byte[1024]; try { int bytesRead = mInStream.read(buffer); if (bytesRead > 0) { String received = new String(buffer, 0, bytesRead); // 把数据回传给所有已注册的Activity broadcastToClients(received); } } catch (IOException e) { e.printStackTrace(); // 读取异常,触发重连 initBluetoothConnection(); } // 延迟100ms后再次执行,实现循环监听 mServiceHandler.postDelayed(this, 100); } }; mServiceHandler.post(readTask); } private void sendToArduino(String data) { if (mOutStream == null) return; try { mOutStream.write(data.getBytes()); mOutStream.flush(); } catch (IOException e) { e.printStackTrace(); } } private void broadcastToClients(String data) { Iterator<Messenger> iterator = mClients.iterator(); while (iterator.hasNext()) { Messenger client = iterator.next(); try { Message msg = Message.obtain(null, MSG_RECEIVE_DATA); msg.obj = data; client.send(msg); } catch (RemoteException e) { // 客户端已断开,移除 iterator.remove(); } } } @Nullable @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } @Override public void onDestroy() { super.onDestroy(); // 释放蓝牙资源 try { if (mInStream != null) mInStream.close(); if (mOutStream != null) mOutStream.close(); if (mSocket != null) mSocket.close(); } catch (IOException e) { e.printStackTrace(); } // 终止后台线程 mCommThread.quit(); } }
2. Activity绑定Service并通信
两个Activity(Configure和Operate)通过相同的逻辑绑定Service,发送指令并接收回传数据:
public class ConfigureActivity extends AppCompatActivity { private Messenger mServiceMessenger; private boolean mIsBound; // 用于接收Service回传消息的客户端Messenger private final Messenger mClientMessenger = new Messenger(new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { if (msg.what == BluetoothCommService.MSG_RECEIVE_DATA) { String data = (String) msg.obj; // 更新UI,比如显示Arduino返回的配置数据 updateConfigUI(data); } } }); private final ServiceConnection mServiceConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mServiceMessenger = new Messenger(service); mIsBound = true; // 注册客户端,告知Service需要回传数据 try { Message msg = Message.obtain(null, BluetoothCommService.MSG_REGISTER_CLIENT); msg.replyTo = mClientMessenger; mServiceMessenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { mServiceMessenger = null; mIsBound = false; } }; @Override protected void onStart() { super.onStart(); // 绑定蓝牙通信Service bindService(new Intent(this, BluetoothCommService.class), mServiceConn, BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); if (mIsBound) { // 取消注册,避免Service继续向已销毁的Activity发消息 try { Message msg = Message.obtain(null, BluetoothCommService.MSG_UNREGISTER_CLIENT); msg.replyTo = mClientMessenger; mServiceMessenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } unbindService(mServiceConn); mIsBound = false; } } // 发送配置数据到Arduino的方法,比如点击保存按钮时调用 private void sendConfigData(String config) { if (!mIsBound || mServiceMessenger == null) return; try { Message msg = Message.obtain(null, BluetoothCommService.MSG_SEND_DATA); msg.obj = config; mServiceMessenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } private void updateConfigUI(String data) { // 实现UI更新逻辑 } }
关键优势
- 蓝牙连接稳定:Service生命周期独立,不会因Activity切换、销毁而中断连接
- 线程安全:所有蓝牙操作都在
HandlerThread中执行,避免UI线程阻塞 - 多Activity共享:两个Activity只需绑定Service即可复用同一通信通道,无需重复初始化蓝牙
- 灵活扩展:可在Service中添加重连、日志、数据解析等逻辑,不侵入Activity代码
内容的提问来源于stack exchange,提问作者Gerald Eberhardt
相关产品推荐
相关产品推荐

