【android】蓝牙对接发送指令无响应以及接收响应信息不完全问题解决(附完整代码)

文章介绍了在对接蓝牙水表编程时遇到的两个问题:一是通过APP下发指令无响应,二是接收响应信息不完全。问题根源在于安卓蓝牙底层write方法对单次发送和接收信息长度的限制。解决方案是通过分段发送和接收方法来处理大于20字节的数据。文章提供了分段接收和发送的代码示例,包括分包接收、拆分数据包、字节数组与十六进制字符串的转换以及发送间隔控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题描述

最近在对接蓝牙水表的代码编写中发现了两个问题:
(1)通过app下发指令无响应,但通过蓝牙调试app下发相同指令有响应;
(2)app接收响应信息不完全。
经查,发现问题出于安卓蓝牙底层,write方法当单次发送、接收信息长度大于20字节时,需要手动分段进行发送与接收,若采用通常的接收与发送方法,则设备只能接收与发送第一段20字节的信息,从而导致以上问题的出现。

二、解决方式

通过简单的分段发送与分段接收拼接即可实现。

三、代码展示
1 分段接收方法

⚠️ 注意:
(1)该部分代码通过比较返回信息中的包长信息与当前接收到的总包长,判断是否完成接收,应根据实际需要修改;
(2)蓝牙初始化、销毁的时候执行this.packageNum = 0; 重置包数;
(3)判断到完成接收后需在分段方法中执行this.packageNum = 0; 重置包数,而不是在下发方法中执行,否则可能造成包数错误,从而导致超时(开发环境未出现但生产环境会出现)。

	private void subpackageReceive(byte[] bytes) {
        packageNum++;
        if (packageNum == 1) {
            packageHex = new StringBuilder();
            packageLength = bytes[1] & (0xff);
        }
        packageHex.append(DataUtils.hex2(bytes, 0, bytes.length - 1));
        if (packageHex.length() == 2 * packageLength) {
            this.packageNum = 0;
            parserData(DataUtils.hexStrToByteArray(packageHex.toString()));
        }
    }
2 分段发送方法
2.1 拆分方法
	public static synchronized List<byte[]> subpackage(byte[] data) {
        List<byte[]> bytesList = new ArrayList<>();
        if (data.length <= 20) {
            bytesList.add(data);
            return bytesList;
        }
        int partNum = data.length / 20;
        int lastPartLen = 20;
        if (data.length % 20 != 0) {
            partNum += 1;
            lastPartLen = data.length % 20;
        }
        for (int n = 0; n < partNum; n++) {
            String dataPart = "";
            if (n == partNum - 1) {
                dataPart = DataUtils.hex2(data, n * 20, lastPartLen - 1);
            } else {
                dataPart = DataUtils.hex2(data, n * 20, 19);
            }
            bytesList.add(DataUtils.hexStrToByteArray(dataPart));
        }
        return bytesList;
    }
2.2 发送方法

⚠️ 注意:
循环执行write发送指令时需间隔一小段时间发送,通过线程休眠实现。

	for (byte[] data : dataList) {
		if (dataList.size() > 1) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
			}
		}
		mBluetoothClient.write(mac, UUID.fromString(serviceUUID), UUID.fromString(writeUUID), data, new BleWriteResponse() {
			@Override
			public void onResponse(int code) {
				if (code == REQUEST_SUCCESS) {
				}
			}
		});
	}
3 工具类
3.1 字节数组转十六进制字符串
	static public String hex2(byte[] buf, int off, int len) {
        StringBuilder sb = new StringBuilder(len * 2);
        for (int j = off; j <= off + len; j++) {
            sb.append(hexString.charAt((buf[j] & 0xf0) >> 4));
            sb.append(hexString.charAt((buf[j] & 0x0f) >> 0));
        }
        return sb.toString();
    }
3.2 十六进制字符串转字节数组
	public static byte[] hexStrToByteArray(String hexStr) {
        if (hexStr == null) {
            return null;
        }
        if (hexStr.length() == 0) {
            return new byte[0];
        }
        byte[] byteArray = new byte[hexStr.length() / 2];
        for (int i = 0; i < byteArray.length; i++) {
            String subStr = hexStr.substring(2 * i, 2 * i + 2);
            byteArray[i] = ((byte) Integer.parseInt(subStr, 16));
        }
        return byteArray;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

布熬夜了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值