Android Studio中Java多Activity全局蓝牙实现求助
作为Android Java开发的过来人,我完全理解你作为新手在跨Activity管理蓝牙连接时的困惑——毕竟蓝牙操作涉及后台生命周期、线程管理还有组件间通信,确实容易踩坑。下面我给你一套清晰、适合新手的实现方案,核心是用Service来托管蓝牙连接,让多个Activity都能安全复用这个连接:
一、核心思路:用Service托管蓝牙连接
为什么选Service?因为Activity的生命周期不稳定(切换页面、退到后台都会销毁/暂停),而Service是后台组件,能在后台持续保持蓝牙连接。多个Activity可以通过绑定Service获取蓝牙操作实例,实现跨页面的蓝牙功能。
二、第一步:创建蓝牙管理Service
我们需要写一个继承自Service的类,封装蓝牙的初始化、连接、数据收发逻辑,同时提供Binder让Activity绑定后调用这些方法。
public class BluetoothService extends Service { // 蓝牙核心对象 private BluetoothAdapter mBluetoothAdapter; private BluetoothSocket mBluetoothSocket; private InputStream mInputStream; private OutputStream mOutputStream; // 用于Activity绑定的Binder private final IBinder mBinder = new LocalBinder(); // 主线程Handler,用于更新UI状态 private Handler mHandler = new Handler(Looper.getMainLooper()); // 内部Binder类,Activity绑定后可获取Service实例 public class LocalBinder extends Binder { BluetoothService getService() { return BluetoothService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } // 初始化蓝牙适配器 public boolean initBluetooth() { mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { sendBroadcast(new Intent("BLUETOOTH_STATUS").putExtra("msg", "设备不支持蓝牙")); return false; } if (!mBluetoothAdapter.isEnabled()) { sendBroadcast(new Intent("BLUETOOTH_STATUS").putExtra("msg", "请开启蓝牙")); return false; } return true; } // 连接蓝牙设备(参数为目标设备MAC地址) public void connectDevice(String deviceMac) { new Thread(() -> { try { BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(deviceMac); // 通用串口UUID,需与设备端一致 UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); mBluetoothSocket = device.createRfcommSocketToServiceRecord(uuid); // 取消扫描避免干扰连接 mBluetoothAdapter.cancelDiscovery(); // 建立连接 mBluetoothSocket.connect(); // 获取读写流 mInputStream = mBluetoothSocket.getInputStream(); mOutputStream = mBluetoothSocket.getOutputStream(); // 通知Activity连接成功 mHandler.post(() -> sendBroadcast(new Intent("BLUETOOTH_STATUS").putExtra("msg", "连接成功"))); // 开始监听接收数据 listenForData(); } catch (IOException e) { e.printStackTrace(); mHandler.post(() -> sendBroadcast(new Intent("BLUETOOTH_STATUS").putExtra("msg", "连接失败:" + e.getMessage()))); // 异常时关闭资源 try { if (mBluetoothSocket != null) mBluetoothSocket.close(); } catch (IOException ex) { ex.printStackTrace(); } } }).start(); } // 监听蓝牙接收的数据 private void listenForData() { new Thread(() -> { byte[] buffer = new byte[1024]; int bytes; while (mBluetoothSocket != null && mInputStream != null) { try { bytes = mInputStream.read(buffer); if (bytes > 0) { String receivedData = new String(buffer, 0, bytes); // 把数据广播给Activity mHandler.post(() -> sendBroadcast(new Intent("BLUETOOTH_DATA").putExtra("data", receivedData))); } } catch (IOException e) { e.printStackTrace(); break; } } }).start(); } // 发送数据到蓝牙设备 public void sendData(String data) { if (mOutputStream != null) { new Thread(() -> { try { mOutputStream.write(data.getBytes()); mOutputStream.flush(); mHandler.post(() -> sendBroadcast(new Intent("BLUETOOTH_STATUS").putExtra("msg", "数据发送成功"))); } catch (IOException e) { e.printStackTrace(); mHandler.post(() -> sendBroadcast(new Intent("BLUETOOTH_STATUS").putExtra("msg", "发送失败:" + e.getMessage()))); } }).start(); } else { sendBroadcast(new Intent("BLUETOOTH_STATUS").putExtra("msg", "未连接蓝牙设备")); } } // 断开蓝牙连接 public void disconnect() { try { if (mInputStream != null) mInputStream.close(); if (mOutputStream != null) mOutputStream.close(); if (mBluetoothSocket != null) mBluetoothSocket.close(); sendBroadcast(new Intent("BLUETOOTH_STATUS").putExtra("msg", "已断开连接")); } catch (IOException e) { e.printStackTrace(); } } @Override public void onDestroy() { super.onDestroy(); disconnect(); } }
三、第二步:在Manifest中注册Service和权限
别忘了在AndroidManifest.xml中添加必要的权限和Service声明:
<!-- 蓝牙权限(适配不同Android版本) --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" /> <!-- 注册蓝牙Service --> <service android:name=".BluetoothService" />
四、第三步:Activity绑定Service并操作蓝牙
每个需要使用蓝牙的Activity都可以绑定Service,绑定后就能调用蓝牙方法,同时通过广播接收状态和数据。
示例1:主Activity(连接蓝牙)
public class MainActivity extends AppCompatActivity { private BluetoothService mBluetoothService; private boolean mBound = false; // 广播接收器,接收Service的状态和数据 private BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if ("BLUETOOTH_STATUS".equals(action)) { String msg = intent.getStringExtra("msg"); Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show(); } else if ("BLUETOOTH_DATA".equals(action)) { String data = intent.getStringExtra("data"); Log.d("Bluetooth", "收到数据:" + data); } } }; // Service连接回调 private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { BluetoothService.LocalBinder binder = (BluetoothService.LocalBinder) service; mBluetoothService = binder.getService(); mBound = true; // 初始化蓝牙 mBluetoothService.initBluetooth(); } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 动态申请蓝牙权限(Android 6.0+必需) requestPermissions(new String[]{Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.ACCESS_FINE_LOCATION}, 100); // 注册广播接收器 IntentFilter filter = new IntentFilter(); filter.addAction("BLUETOOTH_STATUS"); filter.addAction("BLUETOOTH_DATA"); registerReceiver(mBluetoothReceiver, filter); // 绑定Service Intent intent = new Intent(this, BluetoothService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); // 连接蓝牙按钮(替换为你的设备MAC地址) Button connectBtn = findViewById(R.id.connect_btn); connectBtn.setOnClickListener(v -> { if (mBound) { mBluetoothService.connectDevice("00:1A:7D:DA:71:13"); // 替换成目标设备MAC } }); // 跳转第二个Activity,测试跨页面操作 Button goSecondBtn = findViewById(R.id.go_second_btn); goSecondBtn.setOnClickListener(v -> startActivity(new Intent(MainActivity.this, SecondActivity.class))); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(mBluetoothReceiver); // 若需后台保持连接,不要解绑Service // unbindService(mConnection); // mBound = false; } }
示例2:第二个Activity(发送数据)
public class SecondActivity extends AppCompatActivity { private BluetoothService mBluetoothService; private boolean mBound = false; private BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if ("BLUETOOTH_STATUS".equals(intent.getAction())) { String msg = intent.getStringExtra("msg"); Toast.makeText(SecondActivity.this, msg, Toast.LENGTH_SHORT).show(); } } }; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { BluetoothService.LocalBinder binder = (BluetoothService.LocalBinder) service; mBluetoothService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); IntentFilter filter = new IntentFilter("BLUETOOTH_STATUS"); registerReceiver(mBluetoothReceiver, filter); // 绑定Service Intent intent = new Intent(this, BluetoothService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); // 发送数据按钮 Button sendBtn = findViewById(R.id.send_btn); sendBtn.setOnClickListener(v -> { if (mBound) { mBluetoothService.sendData("Hello from Second Activity!"); } }); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(mBluetoothReceiver); } }
五、新手常见坑提示
- 权限问题:务必确保动态权限申请成功,Android 12+的
BLUETOOTH_CONNECT和BLUETOOTH_SCAN权限是必需的。 - UUID一致性:连接时的UUID必须和蓝牙设备端一致,通用串口UUID是
00001101-0000-1000-8000-00805F9B34FB,自定义设备需确认UUID。 - 线程操作:蓝牙的连接、读写必须在子线程进行,否则会触发ANR(应用无响应),上面代码已用
Thread处理。 - Service生命周期:若需持续保持蓝牙连接,不要在Activity退出时解绑Service,仅在App完全退出时解绑即可。
慢慢测试,先确保Service能正常绑定,再测试蓝牙连接,最后验证跨Activity数据收发,遇到问题查看Logcat的错误信息,大部分问题都出在权限、UUID或线程上。
内容的提问来源于stack exchange,提问作者Datalink
相关产品推荐
相关产品推荐

