公司开发了一款健康类 APP,用户可以通过 APP 连接外部蓝牙 BLE 设备采集血糖,血压,体重等多个常见健康类指标。因此 APP 需要同时集成多款设备(多个品牌的血糖仪,血压计,体脂秤等)。每个厂家的设备对接协议是不同的,甚至连同一个设备的不同版本,协议都会有差距。在一个 APP 中跟多个设备对接,甚至在同一个界面中需要处理多个设备,界面跟协议混在一起,成为一个比较头疼的问题。本文对如何在 APP 中支持多设备集成,并且在需要对接新设备的时候,容易扩展现有代码提供了一个比较好的实践思路。
原来在界面 Activity 类中,集成多个设备时候的代码通常如下所示(为了达到说明目的,代码做了很多简化,实际情况中设备对接的协议代码逻辑要复杂的多):
- private DeviceType mConnectedDeviceType; //连接设备类型
- /**
- * 处理集成设备发过来的数据
- * @param uuid
- * @param data
- */
- private void processDeviceData(UUID uuid,byte[] data){
- //首先判断当前连接设备类型,再分别处理
- if (mConnectedDeviceType == DeviceType.A){
- //如果当前连接设备类型为A, 根据本地硬编码的协议处理A类设备
- processDeviceA(UUID uuid,byte[] data);
- }else if (mConnectedDeviceType == DeviceType.B){
- //如果当前连接设备类型为B, 处理B类设备
- processDeviceB(UUID uuid,byte[] data);
- }else if (mConnectedDeviceType == DeviceType.C){
- //如果当前连接设备类型为C, 处理C类设备
- processDeviceC(UUID uuid,byte[] data);
- }
- ...
- }
- /**
- * 处理A类设备的协议交互代码
- * @param uuid
- * @param data
- */
- private void processDeviceA(UUID uuid,byte[] data){
- int step = parseCmdA(uuid, data);
- if (step == 0x1){
- showResultA(data); //显示测量结果
- }else if (step == 0x2){
- writeCmd("cmd2a"); //向连接设备下发数据
- }else if (step == 0x3){
- writeCmd("cmd3a");
- }
- }
- /**
- * 处理B类设备的协议交互代码
- * @param uuid
- * @param data
- */
- private void processDeviceB(UUID uuid,byte[] data){
- int step = parseCmdB(uuid, data);
- if (step == 0x1){
- showResultB(data); //显示测量结果
- }else if (step == 0x2){
- writeCmd("cmd2b"); //向连接设备下发数据
- }else if (step == 0x3){
- writeCmd("cmd3b");
- }
- }
- /**
- * 处理C类设备的协议交互代码
- * @param uuid
- * @param data
- */
- private void processDeviceC(UUID uuid,byte[] data){
- int step = parseCmdC(uuid, data);
- if (step == 0x1){
- writeCmd("cmd2c"); //向连接设备下发数据
- }else if (step == 0x2){
- showResultC(data); //显示测量结果
- }else if (step == 0x3){
- writeCmd("cmd3c");
- }
- }
以上代码可以看出界面跟设备协议是强耦合在一起的。如果需要集成更多的设备那怎么办?原有的类代码势必变得更复杂,难以维护。因此我们需要把设备间的协议交互逻辑与界面进行解耦,以保持单一职责的设计原则:界面只进行步骤和测量结果的更新展示,交互逻辑可以放到其他类中。在这个地方我们可以使用 Adapter 作为设备适配器,把设备间的交互封装到 Adapter 里面去,集成不同设备的时候调用不同的 Adapter 处理即可。
我们如何设计 Adapter 呢?虽然每个设备的交互协议不一样,但是其中一些操作却是共性的,比如一开始总是要连接设备,连接成功后设置指定 UUID 的 notification 或者 indication,然后向外部设备写入数据 (下发指令),或者等待外部设备数据变化上报,交互完成后再断开设备。
因此我们可以把这些共性操作抽象成 DeviceAdapter 接口。DeviceAdatper 接口主要包含上述的常用操作:
来源: