Android BLE 开发问题汇总

作者: 王世军Steven | 来源:发表于2016-12-07 16:11 被阅读358次

    一 设备连接太慢问题 .

    1. 效果最明显的方法:

    将 connectGATT()方法的第二个参数设置成false.如下所示.

    // 第二个参数的作用如下 : 
    // Whether to directly connect to the remote device (false) or to
    // automatically connect as soon as the remote device becomes available (true).
    
    device.connectGatt(mContext,false,mGattCallback)
    

    二 相关回调问题.

    Android BLE 相关的 API 回调都是在发送该操作请求的线程中执行的线程中执行的.
    因此不要让该线程阻塞,否则的话.很多回调都无法执行.

    比如 :

    // 发送数据,写特征值. 会触发 Android 的 onCharacteristicWirte() 回调方法.
    gatt.writeCharacteristic(characteristic)
    
    // 回调方法onCharacteristicWirte执行在上面代码所在的线程中.
    // 因此如果在代码中有阻塞操作.比如
    while(true){
        // ...
    }
    // 就会造成onCharacteristicWirte回调方法无法执行.产生各种不正常的现象.
    
    

    三 Android 数据发送问题.

    1. 发送长度问题.

    在 Android 5.0 以前单次发送/接收数据的最大长度是 20 字节 .
    因此对于数据量较大的数据需要进行分包发送处理 . 特别需要注意的是如果BLE外设
    单次发送的数据量大于 20 字节, Android 只能接收前20个字节的数据.
    后面的数据将会丢失 .

    2. 分包发送

    分包发送要注意不要在当前线程做阻塞处理.否则会出现不可预知的情况. 并且一定要在上次发送数据成功写入(onCharacteristicWrite()回调执行)的情况下再去进行第二次写操作.否则第二次写操作将会失败.

    3. 分包发送示例.

    // 发送数据接口. 
    private int sendData2DeviceInner2(final byte[] data){
        LogUtils.e(TAG,"设置发送参数 : " + FunctionTools.byte2HexString(data));
        mSendDataPackage.initSendTask(Arrays.copyOf(data,data.length));
        // 发送一次数据.
        new Thread(sendDataPackageTask).start();
        return RES_BLE_SUCCESS;
    }
     // 写数据.
    private boolean sendDataInner(byte[] data){
        LogUtils.e(TAG,"sendDataInner当前线程 : " + Thread.currentThread().getId());
        mService = mCurBluetoothGatt.getService(SERVICE_UUID);
        if (!isObjectNull(mBlxService)) {
            mWriteCharacteristic = mBlxService.getCharacteristic(CHARACTERISTIC_WRITE_UUID);
        }
        if (!isObjectNull(mWriteCharacteristic)) {
            mWriteCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
            boolean res = mWriteCharacteristic.setValue(data);
            boolean res1 = mCurBluetoothGatt.writeCharacteristic(mWriteCharacteristic);
            if (res&res1)
                startDevComTimer();
            return res & res1;
        }else{
            LogUtils.e(TAG,"写特征值为空");
            return false;
        }
    }
    // 待发送数据缓存类.
    private sendDataPackage mSendDataPackage = new sendDataPackage();
    private class sendDataPackage {
            // 发送数据
            int sendTotalLen = 0;
            int sendIndex = 0;
            byte[] sendBuffer = new byte[0];
            public void clearSendFlags(){
                sendTotalLen = 0;
                sendIndex = 0;
                sendBuffer = new byte[0];
            }
            public void initSendTask(final byte[] data){
                sendTotalLen = data.length;
                sendIndex = 0;
                sendBuffer = data;
            }
            public byte[] getOnceBuffer(){
                if (sendBuffer.length == 0)
                    return new byte[0];
                int len = MAX_SEND_BYTES_COUNT;
                if (sendTotalLen - sendIndex < MAX_SEND_BYTES_COUNT)
                    len = sendTotalLen - sendIndex;
                // 更新 Index
                sendIndex += len;
    
                return Arrays.copyOfRange(sendBuffer,sendIndex - len,sendIndex);
            }
            public boolean needSend(){
                if (sendBuffer.length == 0 || sendTotalLen == 0)
                    return false;
                if (sendTotalLen == sendIndex )
                    return false;
                return true;
            }
    }
    // 发送数据任务.    
    private Runnable sendDataPackageTask = new Runnable() {
            @Override
            public void run() {
                LogUtils.d(TAG,">>>>>>>>>> 发送数据");
                if (mSendDataPackage.needSend()){
                    if (!sendDataInner(mSendDataPackage.getOnceBuffer())){
                        // 发送数据失败
                        // TODO .......清理标志位
                    }
                }
            }
    };
    
    // 写数据回调实现代码
    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicWrite(gatt, characteristic, status);
        if (status == BluetoothGatt.GATT_SUCCESS) {
            // 写成功
            if (mSendDataPackage.needSend())
                new Thread(sendDataPackageTask).start();
            }
            else
                // 写失败....
    }
    

    四 Android 中重复连接BLE导致设备直接返回STATE_DISCONNECTED的解决办法

    问题描述

    通过使用if(gatt==null)来判断gatt是否被创建过,如果创建过就使用gatt.connect(),重新建立连接,但是在这种情况下测试的结果是重新连接需要花费很长的时间。

    解决办法

    解决办法是通过gatt = device.connectGatt(this, false, gattCallback);
    建立一个新的连接对象,很明显这样的速度要比上一种方法快很多;

    问题描述

    但是,多次创建gatt连接对象的直接结果是创建过6个以上gatt后就会再也连接不上任何设备,原因应该是android中对BLE限制了同时连接的数量为6个.

    解决办法

    在每一次重新连接时都执行一次gatt.close(),关闭上一个连接。有人说为什么不在gatt.disconnect();后加一条gatt.close();呢,原因是如果立即执行gatt.close();会导致gattCallback无法收到STATE_DISCONNECTED的状态。当然,最好的办法是在gattCallback收到STATE_DISCONNECTED后再执行gatt.close();这样逻辑上会更清析一些。

    参考 :

    链接 : http://bbs.eeworld.com.cn/thread-438571-1-1.html

    五 分包发送数据出错问题 .

    问题 :

    有些蓝牙芯片接收数时出现TX的数据被覆盖的问题.导致接收到的数据个别字节发生错误. 因为蓝牙芯中两帧数据中间是需要间隔的.

    解决方法 :

    1. 可以在Android端在分包发送时增加延时操作(100ms较好) .
    2. 在COS程序中增加延时操作(推荐使用的方法).

    相关文章

      网友评论

        本文标题:Android BLE 开发问题汇总

        本文链接:https://www.haomeiwen.com/subject/zvadmttx.html