首先,上框架的连接:https://github.com/Jasonchenlijian/FastBle
转: 作者文章: Android BLE开发详解和FastBle源码解析:https://www.jianshu.com/p/795bb0a08beb
1. BLE 扫描不到设备,也未报错。查看Log显示警告:
Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results
原因: 定位权限未允许。打开系统应用,找到对应的app,把定位权限打开,除了定位权限之后,部分手机需要打开定位开关。
待解决:如何在用户选择:不再询问,之后弹窗打开权限 ,或者打开定位开关。
2.Fastble 写特征值失败:gatt writeCharacteristic fail??
2021-0207-132643:error::startWrite() : 写失败==[0x5a, 0x00, 0x0b, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0xf1, 0x3b]BleException { code=102, description='gatt writeCharacteristic fail'}
出现 此问题之后,会一直写有问题? 要如何处理此问题?
看了一下出错的地方:蓝牙Gatt writeCharacteristic 返回false(bluetoothGatt writeCharacteristic returns false)
BluetoothGatt.class
public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {}.
看百度有人说读写间增加1s的延时再操作。
解决:目前解决办法,是如写失败会增加延时来再写一次。 然后按设备端要求先打开Notify对应的特征值再开始写。
3. 打开Notity, 操作写Write失败。出错类:BleConnector.class, Notify Setting 方法报错。
mNotifier,打开failed,BleException { code=102, description=’gatt writeDescriptor fail’}
2021-0220-111638:error::startWrite() : 写失败==[0x5a, 0x00, 0x05, 0x00, 0x01, 0x1d, 0x01, 0x00, 0x5d, 0xae]BleException { code=102, description=’gatt writeCharacteristic fail’}
原因:未知,1/30概率出现,不知道是否与设备有关。
/**
* notify setting
*/
private boolean setCharacteristicNotification(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
boolean useCharacteristicDescriptor,
boolean enable,
BleNotifyCallback bleNotifyCallback) {
if (gatt == null || characteristic == null) {
notifyMsgInit();
if (bleNotifyCallback != null)
bleNotifyCallback.onNotifyFailure(new OtherException("gatt or characteristic equal null"));
return false;
}
boolean success1 = gatt.setCharacteristicNotification(characteristic, enable);
if (!success1) {
notifyMsgInit();
if (bleNotifyCallback != null)
bleNotifyCallback.onNotifyFailure(new OtherException("gatt setCharacteristicNotification fail"));
return false;
}
BluetoothGattDescriptor descriptor;
if (useCharacteristicDescriptor) {
descriptor = characteristic.getDescriptor(characteristic.getUuid());
} else {
descriptor = characteristic.getDescriptor(formUUID(UUID_CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR));
}
if (descriptor == null) {
notifyMsgInit();
if (bleNotifyCallback != null)
bleNotifyCallback.onNotifyFailure(new OtherException("descriptor equals null"));
return false;
} else {
descriptor.setValue(enable ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE :
BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
boolean success2 = gatt.writeDescriptor(descriptor);
if (!success2) {
notifyMsgInit();
if (bleNotifyCallback != null)
bleNotifyCallback.onNotifyFailure(new OtherException("gatt writeDescriptor fail"));
}
return success2;
}
}
解决方法1: 收到失败监听方法,增加延时再次调用 。
@Override
public void onNotifyFailure(final BleException exception) {
LogUtils.e("mNotifier,打开failed" + exception.toString());
if (null != bleDevice) {
bleDevice.setNotify(false);
startNotify(bleDevcie);
}
}
}
以上收到失败之后不要立即再尝试打开Notify; 我增加一个2s的延时, startNotify(bleDevcie);。
@Override
public void onNotifyFailure(final BleException exception) {
LogUtils.e("mNotifier,打开failed" + exception.toString());
if (null != bleDevice) {
if (connectorHandler != null) {
connectorHandler.postDelayed(new Runnable() {
@Override
public void run() {
bleDevice.setNotify(false);
startNotify(bleDevcie);
}
}, 2000);
}
}
}
其他情况 :设备ble导致Notify打开失败,需要先打开特征值读写功能。
目前参考上面的方法:一般会出现2次Notify打开失败, 但是最终还是能打开成功。
4. OutOfMemoryError BLE通信量大,阻塞主线程其他功能运行,造成Activity打开卡顿。
分析:以下2个ble处理都是用hanler切换回主线程操作。
-
BleBluetooth.class 使用了MainHandler mainHandler = new MainHandler(Looper.getMainLooper());
-
BleConnector.class 使用mHandler = new Handler(Looper.getMainLooper())
- 解决:将以下2个handle切换HandlerThread 子线程处理类。目前大部分功能正常,但是有部分子线程与子线程通信不正常。待解决。
- 切为HandlerThread之后,做OTA升级,需要大量通信,造成OOM问题。splitWriter.class 类每发一个大于20字节的包就会创造一个对象,对象里面包含着子线程。造成内存消耗。
- 见下面报错:(待解决。)
- 2021-03-17 09:59:57.245 21190-30225/com.gtk.darwin W/com.gtk.darwin: Throwing OutOfMemoryError “pthread_create (1040KB stack) failed: Try again”
2021-03-17 09:59:57.247 21190-30225/com.gtk.darwin E/AndroidRuntime: FATAL EXCEPTION: splitWriter
Process: com.gtk.darwin, PID: 21190
java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
at java.lang.Thread.nativeCreate(Native Method)
at java.lang.Thread.start(Thread.java:733)
at com.gtkcep.blelib.bluetooth.BleConnector.<init>(BleConnector.java:47)
at com.gtkcep.blelib.bluetooth.BleBluetooth.newBleConnector(BleBluetooth.java:61)
at com.gtkcep.blelib.bluetooth.SplitWriter.write(SplitWriter.java:89)
at com.gtkcep.blelib.bluetooth.SplitWriter.access$000(SplitWriter.java:20)
at com.gtkcep.blelib.bluetooth.SplitWriter$1.handleMessage(SplitWriter.java:45)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.os.HandlerThread.run(HandlerThread.java:65)
- 2021-03-17 09:59:57.245 21190-30225/com.gtk.darwin W/com.gtk.darwin: Throwing OutOfMemoryError “pthread_create (1040KB stack) failed: Try again”
oom解决:优化方法,SplitWrite.class 频繁创建BleConnector.class改成只创建一个。
- if (null == bleConnector) {
bleConnector = mBleBluetooth.newBleConnector().withUUIDString(mUuid_service, mUuid_write);
}
bleConnector.writeCharacteristic(data, getmCallback(), mUuid_write); - // BleConnector.class 增加释放方法, 在SplitWrite.class发完所有的拆包之后,调用 。并且改原来框架handler, 不要用HandlerThread。
-
// BleConnector.class 增加释放方法 public void release() { try { if (null != mBHandler) { mBHandler.removeCallbacksAndMessages(null); } mBHandler = null; } catch (Exception e) { e.printStackTrace(); } } // ---SpliWriter public class SplitWriter { private HandlerThread mSHandlerThread; private SHandler mSHandler; private BleBluetooth mBleBluetooth; private String mUuid_service; private String mUuid_write; private byte[] mData; private int mCount; private boolean mSendNextWhenLastSuccess; private long mIntervalBetweenTwoPackage; private BleWriteCallback mCallback; private Queue<byte[]> mDataQueue; private int mTotalNum; private BleWriteCallback bleWriteCallback; private BleConnector bleConnector; public SplitWriter() { mSHandlerThread = new HandlerThread("splitWriter"); mSHandlerThread.start(); mSHandler = new SHandler(this, mSHandlerThread.getLooper()); } public void splitWrite(BleBluetooth bleBluetooth, String uuid_service, String uuid_write, byte[] data, boolean sendNextWhenLastSuccess, long intervalBetweenTwoPackage, BleWriteCallback callback) { mBleBluetooth = bleBluetooth; mUuid_service = uuid_service; mUuid_write = uuid_write; mData = data; mSendNextWhenLastSuccess = sendNextWhenLastSuccess; mIntervalBetweenTwoPackage = intervalBetweenTwoPackage; //每个包发送的时间间隔 mCount = BleManager.getInstance().getSplitWriteNum();// 按钮 20个byte来拆开 mCallback = callback; splitWrite(); } private void splitWrite() { if (mData == null) { throw new IllegalArgumentException("data is Null!"); } if (mCount < 1) { throw new IllegalArgumentException("split count should higher than 0!"); } mDataQueue = splitByte(mData, mCount); // 按20个字节拆开放到队列 mTotalNum = mDataQueue.size(); write(); } private void write() { if (mDataQueue.peek() == null) { // Handler循环写,直接队列为空。 release(); return; } LogUtils.json("Write(),当前线程打印。"); byte[] data = mDataQueue.poll(); if (null == bleConnector) { bleConnector = mBleBluetooth.newBleConnector().withUUIDString(mUuid_service, mUuid_write); } bleConnector.writeCharacteristic(data, getmCallback(), mUuid_write); if (!mSendNextWhenLastSuccess) { if (mSHandler == null) return; mSHandler.sendEmptyMessageDelayed(BleMsg.MSG_SPLIT_WRITE_NEXT, mIntervalBetweenTwoPackage); } } private BleWriteCallback getmCallback() { if (null == bleWriteCallback) { bleWriteCallback = new BleWriteCallback() { @Override public void onWriteSuccess(int current, int total, byte[] justWrite) { int position = mTotalNum - mDataQueue.size(); if (mCallback != null) { mCallback.onWriteSuccess(position, mTotalNum, justWrite); } if (mSendNextWhenLastSuccess) { LogUtils.json("SplitWriter 当前线程"); // BLE sub thread 1 if (mSHandler == null) return; mSHandler.sendEmptyMessageDelayed(BleMsg.MSG_SPLIT_WRITE_NEXT, mIntervalBetweenTwoPackage);//包与包写给手环要增加时间间隔 } } @Override public void onWriteFailure(BleException exception) { try { if (mCallback != null) { mCallback.onWriteFailure(new OtherException("exception occur while writing: " + exception.getDescription())); } if (mSendNextWhenLastSuccess) { if (mSHandler == null) return; mSHandler.sendEmptyMessageDelayed(BleMsg.MSG_SPLIT_WRITE_NEXT, mIntervalBetweenTwoPackage); } } catch (Exception e) { e.printStackTrace(); } } }; } return bleWriteCallback; } public void release() { if (null != mSHandlerThread) { mSHandlerThread.quit(); } if (null != mSHandler) { mSHandler.removeCallbacksAndMessages(null); } if (null != bleConnector) { bleConnector.release(); } bleConnector = null; mSHandlerThread = null; mSHandler = null; } /** * 将数据拆成20byte一包,放到队列 * * @param data * @param count * @return */ private static Queue<byte[]> splitByte(byte[] data, int count) { if (count > 20) { LogUtils.w("Be careful: split count beyond 20! Ensure MTU higher than 23!"); } Queue<byte[]> byteQueue = new LinkedList<>(); int pkgCount; if (data.length % count == 0) {//拆开之后,包个数 pkgCount = data.length / count; } else { pkgCount = Math.round(data.length / count + 1); } byte[] dataPkg; int j; if (pkgCount > 0) { for (int i = 0; i < pkgCount; i++) { if (pkgCount == 1 || i == pkgCount - 1) { j = data.length % count == 0 ? count : data.length % count; System.arraycopy(data, i * count, dataPkg = new byte[j], 0, j); } else { System.arraycopy(data, i * count, dataPkg = new byte[count], 0, count); } byteQueue.offer(dataPkg); } } return byteQueue; } private static class SHandler extends Handler { private WeakReference<SplitWriter> reference; public SHandler(SplitWriter splitWriter, Looper looper) { super(looper); reference = new WeakReference<>(splitWriter); } @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); SplitWriter splitWriter = reference.get(); if (null == splitWriter) return; if (msg.what == BleMsg.MSG_SPLIT_WRITE_NEXT) { splitWriter.write(); } } } }
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/101669.html