分享一个兼容多设备的蓝牙Lib框架封装思想(二)

引入

接着上面的讲,现在已经大致知道了怎么使用android api 进行蓝牙连接,可是我们也知道一个蓝牙设备会有好多服务通道(大通道)和下面的数据通道(小通道),每个设备会有很多指令集,往往实际应用中,集成一个蓝牙硬件,光是浏览协议中提供了哪些指令和功能,就已经够花费时间了,更别说集成了。最后终于根据协议,一个一个解析接入完了。这个时候要是老板和产品过来说又要加设备,那之前的代码是不是能够满足再加一个的需求。另外,下一次要再另外一个项目中集成这个设备,是不是又要重新解析接入一遍所有的协议指令。这些问题,光想想,都脑壳疼了。最好有个蓝牙的sdk,直接导入进来可以开发使用,不用在意输入输出指令的解析,那就太好了。于是,就有了下来要讨论的问题。

具体实现

  • 因为要撸这样的一个框架,代码非常多,而且每个蓝牙设备的协议,都不尽相同,所以我尽量按照讲一下整个思路。
    • 设计一个BleManager的管理类,全权处理app中有关蓝牙操作的所有事宜。
    • BleManager与app中的activity或者service 利用java提供的Obervable观察者模式,将所有的数据返回到服务里面或者UI层(我个人的思路是在blemanager和UI层之间在有一个service做衔接,这样就可以在app运行期间,不管在哪个界面,都可以去与蓝牙交互,蓝牙设备有信息,可以直接通知到UI层。)。

连接过程

  • BleManager设计为单例。提供一个init(Context appContext)方法,用于初始化BluetoothAdapter对象,设置为manager的成员变量。
  • 初始化之后是扫描,创建一个扫描的回调,这个回调返回一个list集合或只返回一个设备。
  • BleManager中有四个主要方法,分别为开始扫描,停止扫描,连接设备,设置指令。

    这里写图片描述

  • 然后是连接设备,当用户点击了一个设备条目,我们会拿到这个设备的名字,mac等信息。我们的框架在设计时,需要一个Driver的接口,表示一个所有设备的父类。
  • 创建一个driver包,在包下面有一个driverimpl的实现包。
  • 每一种设备,都有一种设备名字,根据实际情况,可能是手环,心率带等等。那么对应的就需要手环driver和心率带driver。下图中用DriverXXX表示。
  • 创建一个Driver工厂专门生成具体的driver。在连接之前,生成一个具体的driver,保存成manager的成员变量。

        //连接设备。
        public void onConnectDervice(Context appContext, boolean isAutoConnect, MBleDeviceInfo mBleDevice, BleReciveListener listener) {
        //mBleDevice是对系统driver的提取,增加了type类型。在扫描时进行的包装
        String type = mBleDevice.getType();
        driver = DriverFactory.createDriver(type);
        BleDevice remoteDevice = bleAdapter.getRemoteDevice(mBleDevice.getAddress());
        mBluetoothGattCallback = new MBluetoothGattCallback(driver, listener);
        bluetoothGatt = remoteDevice.connectGatt(appContext, isAutoConnect, mBluetoothGattCallback);
    }

    这里写图片描述

    • 需要解释一下MBluetoothGattCallback这个类,他是继承系统api中的BluetoothGattCallback,而BleReciveListener 为在调用层实例化,用于返回蓝牙连接的结果。将driver传入,以方便与将蓝牙的回调分发到具体的设备drvier中进行分析处理。下面贴一个转到driverxxx的代码。这样就可根据具体的设备做具体的数据解析了。
     @Override
     public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            driver.getBleConnactListener()
            .onConnectionStateChange(gatt, status, newState, listener);
        }
    BleConnactListener mBleConnactListener = new BleConnactListener() {
            //返回的接口方法实现。
         //连接状态
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState, BleManager.BleReciveListener listener) {
            Logger.i(TAG, "BleConnactListener : 连接状态" + Thread.currentThread());
            if (status == GATT_SUCCESS && newState == BluetoothGatt.STATE_CONNECTED) {
                listener.onConnResult(true);
            } else {
                //连接失败。
                listener.onConnResult(false);
            }
        }   
    }
    • 注:如果要打开通道,可以在连接成功的回调之前去打开,打开完成,再刷新UI,显示连接成功。因为,有些时候,通道不打开,是没有办法与蓝牙交互数据的。

发送指令

  • 发送指令,调用Manager的setData()方法。其中参数分别表示指令。

        //向设备传输数据。
        public void setData(Perform perfrom) {
            BleCommand command = driver.createCommand(perfrom);
            driver.sendData(bluetoothGatt, command);
        }

    UI层使用的指令接口

    • 交给drvier去构造一个command命令,里面封装有这条指令的服务通道,数据通道,byte数组等信息。
  • createCommand过程

    • 这个方法是传到具体的Driverxxx中实现的,方法中,对于具体指令的创建,交给了一个工厂类。
      这里写图片描述
     //@param performCommand  所需要创建指令的类型
     //@param perfrom  包装参数的父类接口。此处应该传入具体的实现类。
     //@return
    @Override
    public BleCommand createCommond(Perform perfrom) {
        BleCommand cmd = null;
        switch (performCommand) {//这里要分指令进行。所以要用switch。
            case MConstant.PerformCommand.ONE_DAY://设置步距
                if (perfrom instanceof PerfromSetStepDistance) {
                    cmd = new CommandXXXOneDay(perfrom);
                }
                break;
        }
        return cmd;
    }
    • CommandXXXOneDay 这是一个指令类。里面封装了具体的这条指令信息:指令的服务通道,数据通道,byte数据等信息。到这里为止,指令创建完成。

    这里写图片描述

    • 发送指令,还是通过driver来。具体的实现和上一篇中相似。
     @Override
    public void sendData(BleGatt bluetoothGatt, BleCommand command) {
        String serveGallery = command.getServeGallery();
        String gallery = command.getGallery();
        BluetoothGattCharacteristic bluetoothGattCharacteristic =bleGattCharMap.get(serveGallery).get(gallery);
        bluetoothGattCharacteristic.setValue(command.getBytes());
        bluetoothGatt.writeCharacteristic(bluetoothGattCharacteristic);
    }
  • 接收成功的返回

    • 蓝牙数据的回传,在onCharacteristicChanged回调方法中。在下面方法的switch-case中根据蓝牙协议解析具体数据。解析完成,用listener回传到调用层。

       @Override
          public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, final BleManager.BleReciveListener listener) {
              Logger.i(TAG, "BleConnactListener : 蓝牙回传数据接收处理");
              //TODO 解析数据。
              byte[] data = characteristic.getValue();
              if (data != null && data.length > 0) {
                  StringBuilder stringBuilder = new StringBuilder(data.length);
                  for (byte byteChar : data) {
                      stringBuilder.append(String.format("%02X ", byteChar));
                  }
                  String lastData = stringBuilder.toString();
                  String uuid = characteristic.getUuid().toString();
                  switch (uuid) {
                      case MConstant.Uuid.W311N.charUuid0:
                            listener.receiveData(...);
                          break;
                  }
              }
      
          }
    • 返回的数据,依旧是解析好,封装成具体的bean对象传出去。
      这里写图片描述

    总结

    以上,就是大致的思路。

    • 这个框架,可以让调用层不关心具体的指令构建。需要做什么事情,直接传Perform具体实现类(但是这个实现类需是sdk提供的)。
    • bleManager还可以对外提供支持那些设备的方法。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值