RxAndroidBle 写错误和通知特征

RxAndroidBle errors on write & notification characteristic

您好,我是 运行 RxAndroidBle 在服务中。 我将它设置为自动连接,因为设备每 5 分钟唤醒一次并尝试将数据发送到配对设备。我还设置了通知以获取数据。 它有效,但每次断开连接时我都会收到通知错误和写入错误。

03-07 12:37:03.600 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: close()
03-07 12:37:03.600 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: unregisterApp() - mClientIf=6
03-07 12:37:03.604 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: connect() - device: B4:99:4C:67:5E:67, auto: true
03-07 12:37:03.604 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: registerApp()
03-07 12:37:03.604 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: registerApp() - UUID=1a9155ae-aa9c-465e-aacd-3c535c3d32a8
03-07 12:37:03.607 31014-31026/com.lady.viktoria.lightdrip D/BluetoothGatt: onClientRegistered() - status=0 clientIf=6
03-07 12:37:03.610 31014-31027/com.lady.viktoria.lightdrip D/BluetoothGatt: setCharacteristicNotification() - uuid: 0000ffe1-0000-1000-8000-00805f9b34fb enable: false
03-07 12:37:03.610 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Notifications error: BleGattException{macAddress=B4:99:4C:67:5E:67, status=8 (0x08 -> https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.1.0_r1/stack/include/gatt_api.h), bleGattOperationType=BleGattOperation{description='CONNECTION_STATE'}}
03-07 12:37:03.612 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Write error: BleGattException{macAddress=B4:99:4C:67:5E:67, status=8 (0x08 -> https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.1.0_r1/stack/include/gatt_api.h), bleGattOperationType=BleGattOperation{description='CONNECTION_STATE'}}
03-07 12:41:41.296 31014-7238/com.lady.viktoria.lightdrip D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=6 device=B4:99:4C:67:5E:67
03-07 12:41:41.304 31014-31093/com.lady.viktoria.lightdrip V/CgmBleService: Hey, connection has been established!
03-07 12:41:41.314 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: discoverServices() - device: B4:99:4C:67:5E:67
03-07 12:41:41.889 31014-7239/com.lady.viktoria.lightdrip D/BluetoothGatt: onSearchComplete() = Device=B4:99:4C:67:5E:67 Status=0
03-07 12:41:41.900 31014-31093/com.lady.viktoria.lightdrip D/BluetoothGatt: setCharacteristicNotification() - uuid: 0000ffe1-0000-1000-8000-00805f9b34fb enable: true
03-07 12:41:41.941 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Notifications has been set up
03-07 12:41:46.748 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Change: 1500300000002E000000D63CC12B680000000000
03-07 12:41:46.753 31014-31014/com.lady.viktoria.lightdrip I/CgmBleService: Received Data packet
03-07 12:41:46.763 31014-31014/com.lady.viktoria.lightdrip D/GlucoseRecord: create: No calibration yet
03-07 12:41:46.772 31014-31014/com.lady.viktoria.lightdrip I/GlucoseRecord: calculateAgeAdjustedRawValue: RAW VALUE ADJUSTMENT FROM:0.048 TO: 0.06792021355263159
03-07 12:41:46.781 31014-31014/com.lady.viktoria.lightdrip V/GlucoseRecord: glucoseRecord json: {"id":128,"a":0.0,"ageAdjustedRawValue":0.06792021355263159,"b":0.0,"c":0.0,"calculatedValue":0.0,"calculatedValueSlope":0.0,"calibrationFlag":false,"calibration_id":0,"filteredData":0.046,"ra":0.0,"rawData":0.048,"rb":0.0,"rc":0.0,"sensor_id":2,"synced":false,"timeSinceSensorStarted":1.2766377E7,"timestamp":1.488886906748E12}
03-07 12:41:46.782 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Change: 01
03-07 12:41:46.782 31014-31014/com.lady.viktoria.lightdrip D/CgmBleService: Sending Acknowledge Packet, to put wixel to sleep
03-07 12:41:46.791 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Write success
03-07 12:42:01.144 31014-31027/com.lady.viktoria.lightdrip D/BluetoothGatt: onClientConnectionState() - status=8 clientIf=6 device=B4:99:4C:67:5E:67
03-07 12:42:01.147 31014-31027/com.lady.viktoria.lightdrip V/CgmBleService: Connection Failure
03-07 12:42:01.148 31014-31014/com.lady.viktoria.lightdrip D/BluetoothManager: getConnectionState()
03-07 12:42:01.148 31014-31014/com.lady.viktoria.lightdrip D/BluetoothManager: getConnectedDevices
03-07 12:42:01.153 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: close()
03-07 12:42:01.153 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: unregisterApp() - mClientIf=6
03-07 12:42:01.161 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: connect() - device: B4:99:4C:67:5E:67, auto: true
public class CgmBleService extends Service {
private final static String TAG = CgmBleService.class.getSimpleName();

public final static UUID UUID_BG_MEASUREMENT = UUID.fromString(GattAttributes.HM_RX_TX);
public final static String ACTION_BLE_CONNECTED = "ACTION_BLE_CONNECTED";
public final static String ACTION_BLE_DISCONNECTED = "ACTION_BLE_DISCONNECTED";
public final static String ACTION_BLE_DATA_AVAILABLE = "ACTION_BLE_DATA_AVAILABLE";
public final static String EXTRA_BLE_DATA = "EXTRA_BLE_DATA";
public final static String BEACON_SNACKBAR = "BEACON_SNACKBAR";

private RxBleClient rxBleClient;
private RxBleDevice bleDevice;
private AppPreferences mTrayPreferences;
private PublishSubject<Void> disconnectTriggerSubject = PublishSubject.create();
private Observable<RxBleConnection> connectionObservable;
Handler handler;

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);

    handler = new Handler();
    startJobScheduler();

    // get mac address from selected wixelbridge
    mTrayPreferences = new AppPreferences(this);
    final String BTDeviceAddress = mTrayPreferences.getString("BT_MAC_Address", "00:00:00:00:00:00");

    //init rxBleClient
    rxBleClient = RxBleClient.create(this);
    bleDevice = rxBleClient.getBleDevice(BTDeviceAddress);
    // logging for RxBleClient
    RxBleClient.setLogLevel(RxBleLog.INFO);
    connectionObservable = prepareConnectionObservable();
    connect();

    return START_STICKY;
}

private Observable<RxBleConnection> prepareConnectionObservable() {
    return bleDevice
            .establishConnection(true)
            .takeUntil(disconnectTriggerSubject)
            //.compose(bindUntilEvent(PAUSE)
            .doOnUnsubscribe(this::clearSubscription)
            .compose(new ConnectionSharingAdapter());
}

public void connect() {
    if (isConnected()) {
        triggerDisconnect();
        broadcastUpdate(ACTION_BLE_CONNECTED);
    } else {
        connectionObservable.subscribe(this::onConnectionReceived, this::onConnectionFailure);
        broadcastUpdate(ACTION_BLE_DISCONNECTED);
    }
}

public void writeCharacteristic(final ByteBuffer byteBuffer) {
    byte[] bytearray = byteBuffer.array();
    if (isConnected()) {
        connectionObservable
                .flatMap(rxBleConnection -> rxBleConnection
                        .writeCharacteristic(UUID_BG_MEASUREMENT, bytearray))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(bytes -> onWriteSuccess(), this::onWriteFailure);
    }
}

public void writeNotificationCharacteristic() {
    if (isConnected()) {
        connectionObservable
                .flatMap(rxBleConnection -> rxBleConnection.setupNotification(UUID_BG_MEASUREMENT))
                .doOnNext(notificationObservable -> runOnUiThread(this::notificationHasBeenSetUp))
                .flatMap(notificationObservable -> notificationObservable)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::onNotificationReceived, this::onNotificationSetupFailure);
    }
}

private void runOnUiThread(Runnable runnable) {
    handler.post(runnable);
}

private boolean isConnected() {
    return bleDevice.getConnectionState() == RxBleConnection.RxBleConnectionState.CONNECTED;
}

private void clearSubscription() {
    updateUI();
}

private void triggerDisconnect() {
    disconnectTriggerSubject.onNext(null);
}

private void updateUI() {
    //   connectButton.setText(isConnected() ? getString(R.string.disconnect) : getString(R.string.connect));
    //  readButton.setEnabled(isConnected());
    //  writeButton.setEnabled(isConnected());
    // notifyButton.setEnabled(isConnected());
}



private void onConnectionFailure(Throwable throwable) {
    //noinspection ConstantConditions
    Log.v(TAG, "Connection Failure");
    connect();
}

private void onConnectionReceived(RxBleConnection connection) {
    //noinspection ConstantConditions
    Log.v(TAG, "Hey, connection has been established!");
        writeNotificationCharacteristic();
}

private void onWriteSuccess() {
    //noinspection ConstantConditions
    Log.v(TAG, "Write success");
}

private void onWriteFailure(Throwable throwable) {
    //noinspection ConstantConditions
    Log.v(TAG, "Write error: " + throwable);
}

private void onNotificationReceived(byte[] bytes) {
    //noinspection ConstantConditions
    Log.v(TAG, "Change: "  + ConvertHexString.bytesToHex(bytes));
    long timestamp = new Date().getTime();
    int packatlength = bytes[0];
    if (packatlength >= 2) {
        if (CheckTransmitterID(bytes, bytes.length)) {
            TransmitterRecord.create(bytes, bytes.length, timestamp);
        } else {
            broadcastUpdate(BEACON_SNACKBAR);
        }
    } else if (packatlength <= 1) {
        writeAcknowledgePacket();
    }
}

private void onNotificationSetupFailure(Throwable throwable) {
    //noinspection ConstantConditions
    Log.v(TAG, "Notifications error: " + throwable);
}

private void notificationHasBeenSetUp() {
    //noinspection ConstantConditions
    Log.v(TAG, "Notifications has been set up");
}

public boolean CheckTransmitterID(byte[] packet, int len) {
    int DexSrc;
    int TransmitterID;
    ByteBuffer tmpBuffer;
    final String TxId = mTrayPreferences.getString("Transmitter_Id", "00000");
    TransmitterID = ConvertTxID.convertSrc(TxId);

    tmpBuffer = ByteBuffer.allocate(len);
    tmpBuffer.order(ByteOrder.LITTLE_ENDIAN);
    tmpBuffer.put(packet, 0, len);

    if (packet[0] == 7) {
        Log.i(TAG, "Received Beacon packet.");
        broadcastUpdate(BEACON_SNACKBAR);
        writeTxIdPacket(TransmitterID);
        return false;
    } else if (packet[0] >= 21 && packet[1] == 0) {
        Log.i(TAG, "Received Data packet");
        DexSrc = tmpBuffer.getInt(12);
        TransmitterID = ConvertTxID.convertSrc(TxId);
        if (Integer.compare(DexSrc, TransmitterID) != 0) {
            writeTxIdPacket(TransmitterID);
            return false;
        } else {
            return true;
        }
    }
    return false;
}

private void writeTxIdPacket(int TransmitterID) {
    Log.v(TAG, "try to set transmitter ID");
    ByteBuffer txidMessage = ByteBuffer.allocate(6);
    txidMessage.order(ByteOrder.LITTLE_ENDIAN);
    txidMessage.put(0, (byte) 0x06);
    txidMessage.put(1, (byte) 0x01);
    txidMessage.putInt(2, TransmitterID);
    writeCharacteristic(txidMessage);
}

private void writeAcknowledgePacket() {
    Log.d(TAG, "Sending Acknowledge Packet, to put wixel to sleep");
    ByteBuffer ackMessage = ByteBuffer.allocate(2);
    ackMessage.put(0, (byte) 0x02);
    ackMessage.put(1, (byte) 0xF0);
    writeCharacteristic(ackMessage);
}

private void broadcastUpdate(final String action) {
    final Intent intent = new Intent(action);
    sendBroadcast(intent);
}

public void startJobScheduler() {
    final long REFRESH_INTERVAL = 15 * 60 * 1000;
    ComponentName serviceComponent = new ComponentName(this, SchedulerJobService.class);
    JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
    builder.setRequiresDeviceIdle(false);
    builder.setRequiresCharging(false);
    builder.setPeriodic(REFRESH_INTERVAL);
    //builder.setPersisted(true);
    JobScheduler jobScheduler = (JobScheduler) this.getSystemService(Context.JOB_SCHEDULER_SERVICE);
    int result = jobScheduler.schedule(builder.build());
    if (result == JobScheduler.RESULT_SUCCESS) Log.d(TAG, "Job scheduled successfully!");
}

public void stopJobScheduler() {
    JobScheduler jobScheduler = (JobScheduler) this.getSystemService(Context.JOB_SCHEDULER_SERVICE);
    jobScheduler.cancel(0);
}

@Override
public void onDestroy() {
    super.onDestroy();
    Intent broadcastIntent = new Intent("com.lady.viktoria.lightdrip.services.RestartCgmBleService");
    sendBroadcast(broadcastIntent);
    stopJobScheduler();
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}}

当发生独立的断开连接事件时,用户可能仍然订阅了一些与 RxBleConnection 对象相关的可观察对象。由于图书馆经常在没有单一订阅流程的情况下使用——就像你的情况一样——它需要将有关断开连接的信息路由到所有订阅者。这就是为什么你两次得到同样的错误。

感谢@s_noopy 所以我必须做这样的事情:

Subscription writeNotificationSubscription;
Subscription writeCharacteristicSubscription;

public void writeCharacteristic(final ByteBuffer byteBuffer) {
        byte[] bytearray = byteBuffer.array();
        if (isConnected()) {
            writeCharacteristicSubscription = connectionObservable
                    .flatMap(rxBleConnection -> rxBleConnection
                            .writeCharacteristic(UUID_BG_MEASUREMENT, bytearray))
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(bytes -> onWriteSuccess(), this::onWriteFailure);
        }
    }

 private void onConnectionFailure(Throwable throwable) {
        //noinspection ConstantConditions
        Log.v(TAG, "Connection Failure");
        writeCharacteristicSubscription.unsubscribe();
        writeNotificationSubscription.unsubscribe();
        connect();
    }