当前位置:首页 > 行业动态 > 正文

安卓开发之蓝牙连接与数据发送

权限配置

在AndroidManifest.xml中声明必要权限:

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

注意:Android 6.0+需动态申请位置权限(定位权限是蓝牙扫描的依赖条件)。

安卓开发之蓝牙连接与数据发送  第1张


蓝牙适配器初始化

BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
    // 设备不支持蓝牙
    Toast.makeText(this, "设备不支持蓝牙", Toast.LENGTH_SHORT).show();
    finish();
}

开启蓝牙

if (!bluetoothAdapter.isEnabled()) {
    Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}

注意:需处理onActivityResult回调,判断用户是否同意开启。


扫描蓝牙设备

注册广播接收器

private final BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            // 处理发现的设备(如添加到列表)
        }
    }
};

开始扫描

IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(receiver, filter);
bluetoothAdapter.startDiscovery();

停止扫描

bluetoothAdapter.cancelDiscovery();
unregisterReceiver(receiver);

设备配对与连接

配对设备

BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
device.createBond(); // 触发配对流程

注意:需监听BluetoothDevice.ACTION_BOND_STATE_CHANGED广播,确认配对成功后再连接。

创建蓝牙连接

BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
try {
    socket.connect(); // 阻塞式调用,需在子线程执行
} catch (IOException e) {
    e.printStackTrace();
}

数据发送与接收

发送数据

OutputStream outputStream = socket.getOutputStream();
String data = "Hello Bluetooth";
outputStream.write(data.getBytes(StandardCharsets.UTF_8)); // 需处理异常

接收数据

InputStream inputStream = socket.getInputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) != -1) {
    String received = new String(buffer, 0, len, StandardCharsets.UTF_8);
    // 处理接收到的数据
}

注意:接收数据需在子线程执行,避免阻塞主线程。


线程管理与资源释放

读取线程示例

new Thread(() -> {
    InputStream inputStream = socket.getInputStream();
    byte[] buffer = new byte[1024];
    try {
        while ((inputStream.read(buffer)) != -1) {
            // 通过Handler或LiveData更新UI
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}).start();

断开连接

try {
    socket.close(); // 关闭输入输出流和Socket
} catch (IOException e) {
    e.printStackTrace();
}

常见问题与解决方案

问题 解决方案
蓝牙权限被拒导致功能不可用 动态申请位置权限(ACCESS_FINE_LOCATION),并解释权限用途
设备扫描不到目标设备 检查设备可见性(需目标设备开启可见模式)
连接失败或数据传输中断 确保设备已配对,检查UUID是否匹配,处理线程异常
接收数据粘包或乱码 定义数据协议(如添加消息头或固定长度字段)

相关问题与解答

问题1:如何优化蓝牙连接的稳定性?

解答

  1. 重试机制:连接失败时延迟重试(如3秒后重试2次)。
  2. 心跳包:定期发送轻量级数据(如ping)检测连接状态。
  3. 异常处理:捕获IOException并尝试重新连接。
  4. 线程隔离:将读写操作放在独立线程,避免阻塞主线程。

问题2:如何实现蓝牙数据的分包发送?

解答

  1. 拆分数据:将大数据分割为固定大小的数据包(如每包20字节)。
  2. 添加标识:每个数据包添加序号或校验和(如CRC16)。
  3. 接收端重组:按序号拼接数据包,并验证完整性。
  4. 示例代码
    // 发送端分包
    byte[] fullData = "Large Data".getBytes();
    int packetSize = 20;
    for (int i = 0; i < fullData.length; i += packetSize) {
     int len = Math.min(packetSize, fullData.length i);
     outputStream.write(fullData, i, len); // 分批次发送
    }
0