onServicesDiscovered 回调里不能直接执行 write /readDataFromCharacteristic() 或者 enableNotificationOfCharacteristic之类的,而要放到主线程里执行,如 handler.post( … );
如果发现连接上了,service也discover到了,但是始终不能触发onCharacteristicChanged的,一定要查找如下2个重要原因:
1). 一定要gatt.setCharacteristicNotification(characteristic, enable);
2). 如果设置了1).却还是发现没有触发,这个时候比较坑爹了,加上对此Characteristic的descriptor做indication Enable就应该可以了;
for(BluetoothGattDescriptor dp:characteristic().getDescriptors()) {
dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt().writeDescriptor(dp);
}
3.. 不同的机型的discoverService到onServiceDiscovered之间的耗时长短不一,这会导致一个问题:如果蓝牙硬件设备支持离线传输,即有记忆功能,连接上之后多久发送之前的数据的问题。如果连接之上立即发送,那么手机端的onServiceDiscovered尚未触发,这样Characteristic的值就获取不了(因为你的service,Characteristic都尚未初始化好),从而导致失败。
解决的办法有3个:
1)建立一套ACK机制,蓝牙硬件设备不断的广播,直到所有的数据都收到返回的ACK确认才不再广播即可。
2)更好的办法是,当手机端onServiceDiscovered触发后,并且service,Characteristic都初始化好后,发送指令给蓝牙硬件设备(即writeCharacteristic)表示手机端已经准备好,可以发送数据给我了,蓝牙硬件设备收到后再发送数据,这样能很好的保证数据不丢失。
3) 最好的办法是1)和 2)的结合,即发送准备好的指令,然后让智能硬件发送数据,然后在接收数据的过程中,使用ACK机制确保数据没有任何丢失。
4.. Read/Write Characteristic/Descriptor 等都是异步的,即立即返回,等待回调。因此如果Android手机底层自身如果没有做请求的同步顺序执行的话,那么当有很多请求几乎同时进行时,回调顺序是无法保证的。此时就造成错误,这也会导致很多蓝牙4.0不能兼容某些Android的原因,因此需要自己提供一套同步机制,如RequestQueue,来保证request&response 一个接一个高效有序的进行,即下一个request必须等到上一个request的response返回之后再执行。
5.. Read/Write Characteristic/Descriptor/RemoteRssi(),一般在不同的线程中回调。(除了onDescriptorWrite返回的线程与写入线程为同一个线程???)
BluetoothDevice.conncectGatt(),
BluetoothGatt.connect(),
BluetoothGatt.disconnect(),
BluetoothGatt.discoverServices()
最好都在主线程,否则会遇到很多意想不到的麻烦。
6.. BLE的特征一次读写最大长度20字节。
7.. Android手机会对连接过的BLE设备的Services进行缓存,若设备升级后Services等有改动,则程序会出现通讯失败。此时就得刷新缓存,反射调用BluetoothGatt类总的refresh()方法。
8.. startLeScan(UUID[], LeScanCallback)在Android 4.4及以下手机中似乎只支持16位的短UUID,不支持128位。
9.. connectGatt() 在某些三星手机上只能在UI线程调用。
10.. Android L 新API扫描设备换为 startScan(List, ScanSettings, ScanCallback)。
11.. Android M 必须拥有定位权限才能扫描BLE设备。
12.. 一个主设备(例如Android手机)可以同时连接多个从设备(一般为6个,例如智能硬件。超过就连接不上了),一个从设备只能被一个主设备连接,一旦从设备连接上主设备,就停止广播,断开连接则继续广播。在任何时刻都只能最多一个设备在尝试建立连接。如果同时对多个蓝牙设备发起建立Gatt连接请求。如果前面的设备连接失败了,则后面的设备请求会被永远阻塞住,不会有任何连接回调。所以建议:如果要对多个设备发起连接请求,最好是一个接一个的顺序同步请求管理。
13.. 任何出错,超时,用完就马上调用Gatt.disconnect(), Gatt.close()。
14.. 从bindService 到 onServiceConnected 这个回调花费时间较长, onServiceConnected 这个回调很可能在 MainActivity onResume之后才执行, 所以不要指望onResume里去执行扫描,因为此时serviceConnected 回调都尚未执行
15.. getBtAdapter().enable()是异步,立即返回,但从 off 到 on 的过程需要一个时间所以只能监听系统broadcast发出的intent里的state
16.. onCharacteristicWrite … 等等是指本机写数据指令已经成功发送出去,并且智能硬件已经处理完回应回来了,另外,当智能硬件端要求发送的指令有顺序的话,那么这边不能发送速度过快,即不能在onCharacteristicWrite里立即发送下一条指令。例如OAD/OTA等等,字节必须严格按照image的字节顺序发送出去。
17.. 在writeCharacteristic时,若速度过快(例如在OAD时),会发现发送出去的数据有可能不是你自己真正发出去的,在onCharacteristicWrite里打印出可以确定。
18.. App端的关于同一个UUID的2个指令不能同时发出去,这样会导致硬件端无法辨识,所以需要串行发送,即等其中一个发送回调成功之后,再进行下一个。
19.. 多次扫描蓝牙,在华为荣耀,魅族M3 NOTE 中有的机型,会发现多次断开–扫描–断开–扫描… 会扫描不到设备,此时需要在断开连接后,不能立即扫描,而是要先停止扫描后,过2秒再扫描才能扫描到设备。
20.. 扫描尽量不要放在主线程进行,可以放入子线程里。不然有些机型会出现 do too many work in main thread.
-
').addClass('pre-numbering').hide();