From 3cfcb6dc86eccb5cd6543a0809412df0ed3c10d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E5=87=A4=E5=90=89?= Date: Thu, 3 Apr 2025 15:32:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E8=8E=B7=E5=8F=96=E8=93=9D?= =?UTF-8?q?=E7=89=99=E5=88=97=E8=A1=A8=E6=8E=A5=E5=8F=A3=EF=BC=8C=E8=BF=98?= =?UTF-8?q?=E9=9C=80=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../profilometer/core/bluetooth/BleManager.java | 108 +++++++++++++++------ 1 file changed, 80 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleManager.java b/app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleManager.java index 7f7e152..569de73 100644 --- a/app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleManager.java +++ b/app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleManager.java @@ -25,21 +25,37 @@ import androidx.core.content.ContextCompat; import java.util.ArrayList; import java.util.List; +/** + * BleManager 用于管理蓝牙相关的功能,包括权限检查、扫描设备和连接设备。 + * 本类采用单例模式,确保整个应用中只有一个实例。 + */ public class BleManager { private static final String TAG = "BLEManager"; // 单例实例 private static BleManager instance; - private BluetoothManager bluetoothManager; + // Android 系统蓝牙管理器 + private final BluetoothManager bluetoothManager; + // 蓝牙适配器 private BluetoothAdapter bluetoothAdapter; + // 蓝牙低功耗扫描器 private BluetoothLeScanner bluetoothLeScanner; - private List scannedDevices = new ArrayList<>(); + // 保存扫描到的蓝牙设备列表 + private final List scannedDevices = new ArrayList<>(); + // 扫描回调对象 private ScanCallback scanCallback; + // 蓝牙连接操作返回的 BluetoothGatt 对象 private BluetoothGatt bluetoothGatt; - private Context context; + // 应用上下文(使用 ApplicationContext 防止内存泄露) + private final Context context; + /** + * 私有构造函数,防止外部直接实例化。 + * @param context 上下文 + */ private BleManager(Context context) { + // 使用 ApplicationContext 避免内存泄露 this.context = context.getApplicationContext(); bluetoothManager = (BluetoothManager) this.context.getSystemService(Context.BLUETOOTH_SERVICE); if (bluetoothManager != null) { @@ -48,7 +64,9 @@ public class BleManager { } /** - * 获取单例实例 + * 获取单例实例,确保整个应用中只有一个 BleManager 对象。 + * @param context 上下文 + * @return 单例 BleManager 实例 */ public static synchronized BleManager getInstance(Context context) { if (instance == null) { @@ -58,15 +76,20 @@ public class BleManager { } /** - * 辅助方法:检查指定权限是否已被授予 + * 辅助方法:检查指定权限是否已被授予。 + * @param permission 权限名称,例如 Manifest.permission.BLUETOOTH_SCAN + * @return true 表示已授予,false 表示未授予 */ private boolean hasPermission(String permission) { return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED; } /** - * 检查并请求必要权限(例如:位置、BLUETOOTH_SCAN、BLUETOOTH_CONNECT)。 - * 此方法需要在 Activity 中调用,且在 onRequestPermissionsResult 中处理回调。 + * 检查并请求必要的权限(例如:位置权限、BLUETOOTH_SCAN、BLUETOOTH_CONNECT)。 + * 该方法需要在 Activity 中调用,并在 onRequestPermissionsResult 中处理回调。 + * 需要 API 31(Android S)及以上版本。 + * + * @param activity 当前 Activity */ @RequiresApi(api = Build.VERSION_CODES.S) public void checkAndRequestPermissions(Activity activity) { @@ -85,7 +108,12 @@ public class BleManager { } } - + /** + * 提示用户蓝牙未开启。 + * 注意:此方法不自动开启蓝牙,而是直接通过 Toast 提示用户“蓝牙未开启,请先开启蓝牙”。 + * + * @param activity 当前 Activity + */ public void promptAndEnableBluetooth(Activity activity) { if (bluetoothAdapter == null) { Log.e(TAG, "该设备不支持蓝牙"); @@ -94,13 +122,13 @@ public class BleManager { if (bluetoothAdapter.isEnabled()) { return; } - // 直接提示用户蓝牙未开启,无需点击开启 + // 直接提示用户蓝牙未开启,无需弹出对话框要求开启 Toast.makeText(activity, "蓝牙未开启,请先开启蓝牙", Toast.LENGTH_LONG).show(); - startScan(); } /** - * 开始扫描 BLE 设备,扫描结果保存到 scannedDevices 列表中 + * 开始扫描 BLE 设备,扫描结果将保存到 scannedDevices 列表中。 + * 需要确保蓝牙已开启且 BLUETOOTH_SCAN 权限已被授予。 */ @SuppressLint("MissingPermission") public void startScan() { @@ -117,11 +145,14 @@ public class BleManager { Log.e(TAG, "获取 BluetoothLeScanner 失败"); return; } + // 清空上一次扫描的结果 scannedDevices.clear(); + // 定义扫描回调 scanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { BluetoothDevice device = result.getDevice(); + // 添加新设备到列表中,避免重复 if (device != null && !scannedDevices.contains(device)) { scannedDevices.add(device); Log.d(TAG, "发现设备: " + device.getName() + " - " + device.getAddress()); @@ -144,11 +175,13 @@ public class BleManager { Log.e(TAG, "BLE 扫描失败,错误码:" + errorCode); } }; + // 开始扫描 bluetoothLeScanner.startScan(scanCallback); } /** - * 停止 BLE 设备扫描 + * 停止 BLE 设备扫描。 + * 需要确保 BLUETOOTH_SCAN 权限已被授予。 */ @SuppressLint("MissingPermission") public void stopScan() { @@ -166,39 +199,58 @@ public class BleManager { } /** - * 返回内部扫描到的设备列表,直接返回 List + * 返回当前扫描到的设备列表。 + * 直接返回内部保存的 List 对象。 + * + * @return 蓝牙设备列表 */ public List getScannedDevices() { return scannedDevices; } /** - * 判断是否已有蓝牙设备连接(简单判断 BluetoothGatt 是否非空) + * 判断是否已经有设备建立了蓝牙连接。 + * 这里通过 BluetoothGatt 是否为 null 进行简单判断。 + * + * @return 如果已有设备连接返回 true,否则返回 false */ public boolean isConnected() { return bluetoothGatt != null; } /** - * 尝试连接指定的 BLE 设备 + * 尝试连接指定的 BLE 设备。 + * 传入设备的 MAC 地址,通过 bluetoothAdapter.getRemoteDevice() 获取 BluetoothDevice 对象,再调用 connectGatt 进行连接。 + * + * @param macAddress 设备的 MAC 地址字符串 */ @SuppressLint("MissingPermission") - public void connectToDevice(BluetoothDevice device) { - if (device == null) return; + public void connectToDevice(String macAddress) { + if (macAddress == null || macAddress.isEmpty()) { + Log.e(TAG, "MAC 地址为空"); + return; + } if (!hasPermission(Manifest.permission.BLUETOOTH_CONNECT)) { Log.e(TAG, "BLUETOOTH_CONNECT 权限未授予"); return; } - bluetoothGatt = device.connectGatt(context, false, new BluetoothGattCallback() { - @Override - public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { - if (newState == BluetoothProfile.STATE_CONNECTED) { - Log.d(TAG, "设备已连接: " + device.getName()); - } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { - Log.d(TAG, "设备已断开: " + device.getName()); - bluetoothGatt = null; + try { + // 根据 MAC 地址获取 BluetoothDevice 对象 + BluetoothDevice device = bluetoothAdapter.getRemoteDevice(macAddress); + // 建立蓝牙连接,connectGatt 为异步操作 + bluetoothGatt = device.connectGatt(context, false, new BluetoothGattCallback() { + @Override + public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { + if (newState == BluetoothProfile.STATE_CONNECTED) { + Log.d(TAG, "设备已连接: " + device.getName()); + } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { + Log.d(TAG, "设备已断开: " + device.getName()); + bluetoothGatt = null; + } } - } - }); + }); + } catch (IllegalArgumentException e) { + Log.e(TAG, "无效的 MAC 地址: " + macAddress, e); + } } -} \ No newline at end of file +}