BLE总结,带你彻底搞懂Android启动速度优化

本文详细介绍了Android应用中与蓝牙设备通信的关键组件,包括BluetoothGattService(服务)、BluetoothGattCharacteristic(特性)和BluetoothGattCallback(回调),展示了如何通过这些组件进行连接、读写操作以及启用通知。同时还讨论了重连机制和优化策略,以提高用户体验和电池效率。
摘要由CSDN通过智能技术生成
  • 1

  • 2

  • 3

BluetoothGattService

蓝牙设备所拥有的服务。在这里比喻成 班级 吧。bluetoothdevice就比喻成学校吧。 一个学校可以有很多个班级。班级 根据UUID来区别。

BluetoothGattCharacteristic

蓝牙设备所拥有的特征。比喻成 学生。 一个班级里也可以有很多个学生。学生也是根据UUID 来区别

当你需要用手机来和蓝牙设备通信的时候,就相当于 你想 和一个学生交流,你得先知道 这个学生的学号,所在班级号,就是开发中的所说的CharacUUID, ServiceUUID

BluetoothGattCallback

所有操作的回调函数。

private BluetoothGattCallback gattCallback = new BluetoothGattCallback() {

@Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); //收到设备notify值 (设备上报值) } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); //读取到值 } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); if (status == BluetoothGatt.GATT_SUCCESS) { //write成功(发送值成功) } } @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); if (status == BluetoothGatt.GATT_SUCCESS) { if (newState == BluetoothGatt.STATE_CONNECTED) { // 连接成功 } else if (newState == BluetoothGatt.STATE_DISCONNECTED) { // 断开连接 } } } @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorRead(gatt, descriptor, status); } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorWrite(gatt, descriptor, status); } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { super.onReadRemoteRssi(gatt, rssi, status); if (status == BluetoothGatt.GATT_SUCCESS) { //获取到RSSI, RSSI 正常情况下 是 一个 负值,如 -33 ; 这个值的绝对值越小,代表设备离手机越近 //通过mBluetoothGatt.readRemoteRssi();来获取 } } @Override public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { super.onReliableWriteCompleted(gatt, status); } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); if (status == BluetoothGatt.GATT_SUCCESS) { //寻找到服务 } } }; --------------------------------------------------------------------------------------------------------------------------------------- 当调用了连接函数 mBluetoothGatt = bluetoothDevice.connectGatt(this.context, false, gattCallback);之后, 如果连接成功就会 走到 连接状态回调: @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (status == BluetoothGatt.GATT_SUCCESS) { //首先判断这个status 如果等于 BluetoothGatt.GATT_SUCCESS(value=0)代表这个回调是正常的, //如果不等于 0,那边就代表没有成功,也不需要进行其他操作了, // 连接成功和断开连接都会走到这里 if (newState == BluetoothGatt.STATE_CONNECTED) { // 连接成功 //连接成功之后,我们应该立刻去寻找服务(上面提到的BluetoothGattService),只有寻找到服务之后,才可以和设备进行通信 gatt.discoverServices();// 寻找服务 } else if (newState == BluetoothGatt.STATE_DISCONNECTED) { // 断开连接 } } } 当判断到连接成功之后,会去寻找服务, 这个过程是异步的,会耗点时间,当寻找到服务之后,会走到回调: @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); if (status == BluetoothGatt.GATT_SUCCESS) { //寻找到服务 //寻找服务之后,我们就可以和设备进行通信,比如下发配置值,获取设备电量什么的 readBatrery(); //读取电量操作 sendSetting(); //下发配置值 } } /***读操作***/ void readBatrery(){ //如上面所说,想要和一个学生通信,先知道他的班级(ServiceUUID)和学号(CharacUUID) BluetoothGattService batteryService=mBluetoothGatt.getService(UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb")); //此处的0000180f...是举例,实际开发需要询问硬件那边 if(batteryService!=null){ BluetoothGattCharacteristic batteryCharacteristic=batteryService.getCharacteristic(UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb"));//此处的00002a19...是举例,实际开发需要询问硬件那边 if(batteryCharacteristic!=null){ mBluetoothGatt.readCharacteristic(batteryCharacteristic); //读取电量, 这是读取batteryCharacteristic值的方法,读取其他的值也是如此,只是它们的ServiceUUID 和CharacUUID不一样 } } } 如果读取电量(或者读取其他值)成功之后 ,会来到 回调: @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); //读取到值,根据UUID来判断读到的是什么值 if (characteristic.getUuid().toString() .equals("00002a19-0000-1000-8000-00805f9b34fb")) {// 获取到电量 int battery = characteristic.getValue()[0]; } } /***写操作***/ void sendSetting(){ BluetoothGattService sendService=mBluetoothGatt.getService(UUID.fromString("00001805-0000-1000-8000-00805f9b34fb"));//此处的00001805...是举例,实际开发需要询问硬件那边 if(sendService!=null){ BluetoothGattCharacteristic sendCharacteristic=sendService.getCharacteristic(UUID.fromString("00002a08-0000-1000-8000-00805f9b34fb"));//此处的00002a08...是举例,实际开发需要询问硬件那边 if(sendCharacteristic!=null){ sendCharacteristic.setValue(new byte[] { 0x01,0x20,0x03 });//随便举个数据 mBluetoothGatt.writeCharacteristic(sendCharacteristic);//写命令到设备, } } } 如果下发配置成功之后,会来到回调: @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); if (status == BluetoothGatt.GATT_SUCCESS) { //write成功(发送值成功),可以根据 characteristic.getValue()来判断是哪个值发送成功了,比如 连接上设备之后你有一大串命令需要下发,你调用多次写命令, 这样你需要判断是不是所有命令都成功了,因为android不太稳定,有必要来check命令是否成功,否则你会发现你明明调用 写命令,但是设备那边不响应 } } 讲解完读写操作,还有一个重要操作 就是 Notify(通知) notify 就是让设备 可以发送通知给你,也可以说上报值给你(发送命令给你) 首先你得打开设备的通知功能: //参数 enable 就是打开还是关闭, characteristic就是你想让具有通知功能的BluetoothGattCharacteristic private boolean enableNotification(boolean enable, BluetoothGattCharacteristic characteristic) { if (mBluetoothGatt == null || characteristic == null) return false; if (!mBluetoothGatt.setCharacteristicNotification(characteristic, enable)) return false; BluetoothGattDescriptor clientConfig = characteristic .getDescriptor(UUIDUtils.CCC); if (clientConfig == null) return false; if (enable) { clientConfig .setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); } else { clientConfig .setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); } return mBluetoothGatt.writeDescriptor(clientConfig); } 一旦设备那边notify 数据给你,你会在回调里收到: @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); //收到设备notify值 (设备上报值),根据 characteristic.getUUID()来判断是谁发送值给你,根据characteristic.getValue()来获取这个值 }

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

  • 56

  • 57

  • 58

  • 59

  • 60

  • 61

  • 62

  • 63

  • 64

  • 65

  • 66

  • 67

  • 68

  • 69

  • 70

  • 71

  • 72

  • 73

  • 74

  • 75

  • 76

  • 77

  • 78

  • 79

  • 80

  • 81

  • 82

  • 83

  • 84

  • 85

  • 86

  • 87

  • 88

  • 89

  • 90

  • 91

  • 92

  • 93

  • 94

  • 95

  • 96

  • 97

  • 98

  • 99

  • 100

  • 101

  • 102

  • 103

  • 104

  • 105

  • 106

  • 107

  • 108

  • 109

  • 110

  • 111

  • 112

  • 113

  • 114

  • 115

  • 116

  • 117

  • 118

  • 119

  • 120

  • 121

  • 122

  • 123

  • 124

  • 125

  • 126

  • 127

  • 128

  • 129

  • 130

  • 131

  • 132

  • 133

  • 134

  • 135

  • 136

  • 137

  • 138

  • 139

  • 140

  • 141

  • 142

  • 143

  • 144

  • 145

  • 146

  • 147

  • 148

  • 149

  • 150

  • 151

  • 152

  • 153

  • 154

  • 155

  • 156

  • 157

  • 158

  • 159

  • 160

  • 161

  • 162

  • 163

  • 164

  • 165

  • 166

  • 167

  • 168

  • 169

  • 170

  • 171

  • 172

  • 173

  • 174

  • 175

  • 176

  • 177

  • 178

  • 179

  • 180

  • 181

  • 182

  • 183

  • 184

  • 185

  • 186

  • 187

  • 188

  • 189

  • 190

  • 191

  • 192

  • 193

  • 194

  • 195

  • 196

  • 197

=以上属于BLE基本的操作,下面是进阶================

  1. 关于发送命令, 比如刚连接上设备,你会把很多配置都发送给设备,此时可能会调用多次 write操作,这个时候你应该需要在 write操作之间 加点间隔 例如开启线程,用 Thread.sleep(150), 因为只有收到onCharacteristicWrite回调之后才代表你的值成功了,如果

不加间隔,你会发现可能只会成功一个值。目前测试下来,我才用的是间隔150毫秒比较好,不会太慢,成功率也会高, 可自己实践慢慢调试,这个数值还与设备端update速率有关

在Write 操作的时候,还有个办法可以增快下发速度,且不需要加sleep

就是设置characteristic .setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); Wrtite characteristic without requiring a response by the remote device, 就是不需 要回复,这样速度会快,测试下来连续发送9个数据,设备端那边打印数据都收到且是正确的,但回调值有点奇怪:

图1 是我的发送指令 ,连续无间隔发送9个命令:

图2,3是 onCharacteristicWrite 回调打印信息:

从图片看出,有的值没有收到 onCharacteristicWrite 回调,如第一个值 { 1, 0x08, 3 } ,有的值回调了2次 如 { 1, 0x04, 3 },可能会觉得有的值没有发送成功吧?

  • 1

  • 2

以下是 设备端收到值的打印信息:(0x00FF是用做分隔符,可忽略)

可以发现,9个值均接收正常, 所以说 这种快速发值,还是有点可靠的。测试的不多,各位可斟酌使用

  • 1

  • 2

2.关于重连

提到ble,估计想的最多的就是重连了。重连当然得是自动重连。可能有人想到的的就是 断开之后再来一次bluetoothDevice.connectGatt(this.context, false, gattCallback)行不行?

先看看官方的说法 :

官方说 mbluetoothGatt.connect()方法就是用来重连的, 只要你断线之后 调用此方法就好了。 测试下来 确实可以,但不同手机体验不一样, 但大家知道 android 碎片化现象很严重,什么 flyme,什么MIUI,emotion之类的。所以需要做什么适配。 只调用 mbluetoothGatt.connect()来重连,我归类为2种 三星 手机 和 非三星手机。 三星手机现象: 重连非常迅速 ,断开之后,只要一回到有效范围内。立马重连成功。 就算隔一天你回来 靠近设备,立马连接成功。这简直就是太棒了。 非三星手机现象: 也会重连成功,但这时间无法保证,有可能1分钟,有可能5分钟,10分钟,甚至就连不上了。体验非常不好。 说一下解决办法: 判断手机是否为三星手机: private boolean checkIsSamsung() { //此方法是我自行使用众多三星手机总结出来,不一定很准确 String brand = android.os.Build.BRAND; Log.e("", " brand:" + brand); if (brand.toLowerCase().equals("samsung")) { return true; } return false; } 在设备断线之后, 我们需要进入重连流程: if(isSamsung){ //这里最好 Sleep 300毫秒,测试发现有时候三星手机断线之后立马调用connect会容易蓝牙奔溃 mbluetoothGatt.connect(); }else{ connectGatt(); handler.removeCallbacks(runnableReconnect ); handler.postDelayed(runnableReconnect , 30*1000); } 流程就是断线之后 三星手机 调用官方的connect()函数,而非三星手机 使用 connectGatt() ,相当于重新建立连接,并且每30s去循环询问是否需要重新建立连接,如果已经连接好,取消这个循环。这样能保证过一天回来你也有机会重连上,非三星手机通过这个方法重连体验特别好,也可以达到回来之后瞬间连接的效果 这样的方案目前是比较好的,手机APP也可以很省电。,像很多其他的防丢器类APP,比如nut.研究过这个app,这个软件总是在扫描,一直scan,不管你连上还是不连上。 android的scan是很耗电的,app功能完善之后同时也要考虑电量优化。 这里测试过 手机的耗电量,用示波器来接手机测试的, 三星断线之后 重连的阶段,耗电量大概在20ma-30ma(锁屏电量 3ma), 魅族MX2 在30s循环期间,耗电量大概在15ma(锁屏电量 15ma), 这里推测三星的connect()期间它系统自己在后台使用低频率的扫描,这样可以使他重连是很快的。scan就要耗电,所以它电量会比锁屏上升一点。 魅族MX2采用每30s重新建立连接,没有scan,基本没有额外耗电。 这种 重连流程 用身边的手机 三星S3,S4,note2,MX2,M3,Nexus5测试过都很好用。亲们也可以用其他测试一下。 public void connectGatt() { if (bluetoothDevice != null) { if (mBluetoothGatt != null) { mBluetoothGatt.close(); mBluetoothGatt.disconnect(); mBluetoothGatt = null; } mBluetoothGatt = bluetoothDevice.connectGatt(this.context, false, gattCallback); } else { Log.e(tagString, "the bluetoothDevice is null, please reset the bluetoothDevice"); } } Runnable runnableReconnect = new Runnable() { @Override public void run() { if (! isConnected() ) { handler.postDelayed(this, 30 * 1000); connectGatt(); } } }; 先保存一下,有空再继续写。欢迎各位一起交流

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49
    自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后我想说

为什么很多程序员做不了架构师?
1、良好健康的职业规划很重要,但大多数人都忽略了
2、学习的习惯很重要,持之以恒才是正解。
3、编程思维没能提升一个台阶,局限在了编码,业务,没考虑过选型、扩展
4、身边没有好的架构师引导、培养。所处的圈子对程序员的成长影响巨大。

金九银十面试季,跳槽季,整理面试题已经成了我多年的习惯!在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

m/2024/03/13/H4lCoPEF.jpg" />

最后我想说

为什么很多程序员做不了架构师?
1、良好健康的职业规划很重要,但大多数人都忽略了
2、学习的习惯很重要,持之以恒才是正解。
3、编程思维没能提升一个台阶,局限在了编码,业务,没考虑过选型、扩展
4、身边没有好的架构师引导、培养。所处的圈子对程序员的成长影响巨大。

金九银十面试季,跳槽季,整理面试题已经成了我多年的习惯!在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

[外链图片转存中…(img-kJY8JY56-1712482905335)]

里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值