Android:主Activity与自定义传感器类的蓝牙回调通信问题
问题解答:BluetoothGattCallback触发时调用主Activity方法的实现方式
当然可以实现!不过得注意Android的线程模型和内存泄漏问题,下面给你几种靠谱的实现方案,适配不同的开发场景:
1. 接口回调(最推荐,解耦性强)
这是Android开发中最常用的解耦方式,通过定义回调接口,让传感器类和主Activity之间通过接口通信,避免直接持有Activity引用。
步骤1:定义回调接口
public interface GattCallbackListener { void onGattDeviceConnected(String macAddress); void onGattDataReceived(String macAddress, byte[] data); // 可根据需求扩展更多回调方法,比如连接断开、特征值写入结果等 }
步骤2:在自定义传感器类中持有接口引用
public class CustomSensor { private String macAddress; private String deviceName; private BluetoothGattCallback gattCallback; private GattCallbackListener listener; // 提供设置监听器的方法 public void setGattCallbackListener(GattCallbackListener listener) { this.listener = listener; } private void initGattCallback() { gattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); // 触发回调前先判空,避免空指针 if (newState == BluetoothProfile.STATE_CONNECTED && listener != null) { listener.onGattDeviceConnected(macAddress); } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); if (status == BluetoothGatt.GATT_SUCCESS && listener != null) { listener.onGattDataReceived(macAddress, characteristic.getValue()); } } }; } }
步骤3:主Activity实现接口并绑定监听器
public class MainActivity extends AppCompatActivity implements GattCallbackListener { private ArrayList<CustomSensor> sensorList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 创建传感器实例并绑定监听器 CustomSensor sensor = new CustomSensor(); sensor.setGattCallbackListener(this); sensorList.add(sensor); } @Override public void onGattDeviceConnected(String macAddress) { // 注意:BluetoothGattCallback的方法运行在后台线程,更新UI必须切换到主线程 runOnUiThread(() -> { Toast.makeText(this, "设备 " + macAddress + " 已连接", Toast.LENGTH_SHORT).show(); // 这里可以做UI更新、数据记录等操作 }); } @Override public void onGattDataReceived(String macAddress, byte[] data) { runOnUiThread(() -> { // 处理收到的蓝牙设备数据,比如解析后显示在列表中 }); } }
2. 弱引用(适合简单场景,避免内存泄漏)
如果不想用接口,也可以让传感器类持有主Activity的弱引用,这样不会因为传感器实例长期存在导致Activity内存泄漏。
public class CustomSensor { private WeakReference<MainActivity> activityWeakRef; private BluetoothGattCallback gattCallback; public CustomSensor(MainActivity activity) { this.activityWeakRef = new WeakReference<>(activity); initGattCallback(); } private void initGattCallback() { gattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); MainActivity activity = activityWeakRef.get(); // 检查Activity是否存活,避免操作已销毁的界面 if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) { activity.onGattDeviceConnected(macAddress); } } }; } }
然后在主Activity中定义对应的处理方法:
public void onGattDeviceConnected(String macAddress) { runOnUiThread(() -> { // 处理连接逻辑 }); }
3. LiveData(适配MVVM架构)
如果你的项目采用MVVM架构,用LiveData传递状态和数据是更优雅的方式,LiveData会自动处理线程切换和生命周期感知,避免内存泄漏。
传感器类中定义LiveData
public class CustomSensor { private MutableLiveData<SensorConnectionState> connectionStateLiveData = new MutableLiveData<>(); private MutableLiveData<SensorData> dataLiveData = new MutableLiveData<>(); private void initGattCallback() { gattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); // 用postValue在后台线程更新LiveData connectionStateLiveData.postValue(new SensorConnectionState(macAddress, newState)); } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); if (status == BluetoothGatt.GATT_SUCCESS) { dataLiveData.postValue(new SensorData(macAddress, characteristic.getValue())); } } }; } // 对外提供不可变的LiveData public LiveData<SensorConnectionState> getConnectionStateLiveData() { return connectionStateLiveData; } public LiveData<SensorData> getDataLiveData() { return dataLiveData; } // 定义数据实体类 public static class SensorConnectionState { public String macAddress; public int state; // 构造方法省略 } public static class SensorData { public String macAddress; public byte[] data; // 构造方法省略 } }
主Activity中观察LiveData
sensor.getConnectionStateLiveData().observe(this, state -> { // LiveData自动切换到主线程,无需手动调用runOnUiThread Toast.makeText(this, "设备 " + state.macAddress + " 状态更新:" + state.state, Toast.LENGTH_SHORT).show(); });
关键注意事项
- 内存泄漏防护:无论用哪种方式,在Activity销毁时(比如
onDestroy()方法中),都要遍历sensorList,调用bluetoothGatt.close()释放蓝牙连接,并清空监听器或弱引用。 - 线程切换:BluetoothGatt的所有回调方法都运行在后台线程,直接操作UI会导致崩溃,必须切换到主线程处理UI更新。
- 多设备区分:每个
CustomSensor实例要绑定唯一的MAC地址,这样回调时能准确识别是哪台设备触发的事件。
内容的提问来源于stack exchange,提问作者C.Cordier
相关产品推荐
相关产品推荐

