rxandroidble: устройство отключено на долгое время: приложение переходит в спящий режим

Я использую rxandroidble, используя autoconnect = true, чтобы постоянно отслеживать данные с датчика. Приложение постоянно сканирует датчики, к которым оно было подключено ранее.

Мониторинг данных и сканирование датчиков должны продолжаться всю ночь, даже если телефон не подключен к источнику питания.

Если датчик подключен вечером, приложение останется подключенным всю ночь, даже если оно отключится на мгновение.

Однако, если датчик отключен на 6 часов в течение ночи (потому что я вытащил аккумулятор датчика), а затем я снова подключил аккумулятор датчика утром, телефон не будет повторно подключаться к датчику.

Я постоянно сканирую каждые 8 ​​секунд новые датчики в службе Android, но это не WakefulService и не запускается WakefulIntent. Так должно быть?

Есть идеи, что может происходить? Разработан ли rxandroidble для продолжения сканирования датчиков в этой ситуации (устройство подключается, выходит за пределы диапазона в течение 8 часов, а затем возвращается в диапазон)? Или мне нужно вручную попытаться повторно подключиться после отключения, и тогда rxandroid будет постоянно пытаться подключиться.

Вот мой скан-код:

    public boolean scanForDevices(boolean on){


    if(on){
        if (!mBluetoothAdapter.isEnabled()) {
            Log.e(TAG, "scanForDevices: bluetooth not enabled, scan failed" );
            return false; // bluetooth disabled
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

            if (TheApplication.getInstance().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                Log.e(TAG, "scanForDevices: ACCESS_COARSE_LOCATION permission not granted, scan failed" );
                return false; // App doesn't have permission granted
            }
        }

        if (isScanning()) {
            scanSubscription.unsubscribe();
        } else {

            scanSubscription = RxBleClientSingleton.getInstance().getRxBleClient().scanBleDevices()
                    .observeOn(AndroidSchedulers.mainThread())
                    .doOnError(this::onScanFailure)
                    .doOnUnsubscribe(this::clearSubscription)
                    .subscribe(this::onScanResult, this::onScanFailure);


            //Ensure we won't Scan forever (save battery)
            if (EnablePeriodicScan == true) {
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (isScanning())
                            scanForDevices(false);
                    }
                }, 4000);
            }

        }
    }else{
        //Turn scanning off
        if(isScanning()){
            scanSubscription.unsubscribe();
        }
    }
    return true;
}

и вот мой код подключения:

public void RxBleConnect() {



    autoConnectSetting = true;



    if (false == sensorConnectionState.equals(SensorConnectionState.Disconnected)) {
        Log.d(TAG, "RxBleConnect: cannot connect, #" + allowReconnect + " : " + macAddress + " isn't disconnected, currently in " + sensorConnectionState.toString() );

        if ((sensorConnectionState.equals(SensorConnectionState.Connected)) &&  (allowReconnect > 15)) { /// reached our limit even though we are connected?
            allowReconnect = 0; // reset count
            Disconnect(); // disconnect sensor.
            Log.d(TAG, "RxBleConnect: someone keeps knocking, appears that " + macAddress + " isn't as connected as we thought.");
        }
        allowReconnect ++;

        return; // dont reattempt connection if already attempting to connect
    }

    Log.d(TAG, "RxBleConnect: connecting to sensor....");

    SystemClock.sleep(400);


    connectionObservable  =
            bleDevice.establishConnection(TheApplication.getInstance(), autoConnectSetting)

            .compose(new ConnectionSharingAdapter())
            .observeOn(AndroidSchedulers.mainThread())


            .doOnUnsubscribe(this::RxBleDisconnect)
            .takeUntil(disconnectTriggerSubject)
            .doOnError(throwable -> {
                Log.d(TAG, "rxBleConnection doOnError: " + throwable);
                Disconnect(); // triggerDisconnect();
            });



    connectionSubscription = connectionObservable
            .flatMap(RxBleConnection::discoverServices)
            .subscribe(this::RxBleOnConnectionReceived, this::RxBleOnConnectionFailure);



}

Если состояние подключения меняется на отключение, я не пытаюсь повторно подключиться вручную; сканирование или автоматическое подключение должны решить эту проблему, верно?

Я отключил «Оптимизацию приложений», также известный как режим дремоты, для приложения в настройках батареи Android, но я не знаю, делает ли это что-нибудь.

РЕДАКТИРОВАТЬ 1: Вот мои журналы .... мы подключаемся нормально в первый раз, затем мы пытаемся подключиться, а затем немедленно отключаемся:

>>> FIRST CONNECTION <<<
12-09 21:23:46.904 8992-8992/appName D/PeripheralManager: RxBleConnect: connecting to sensor...., auto connect = false
onConnectionStateChange newState=2 status=0
12-09 21:23:09.298 8992-8992/appName D/PeripheralManager: onConnectionStateChange: new state RxBleConnectionState{CONNECTED}
12-09 21:23:46.831 8992-9004/appName D/BluetoothGatt: onClientConnectionState() - status=8 clientIf=5 device=E0:CF:8D:98:69:6A
12-09 21:23:46.832 8992-9004/appName D/RxBle#BluetoothGatt: onConnectionStateChange newState=0 status=8
12-09 21:23:46.897 8992-8992/appName D/PeripheralManager: onConnectionStateChange: new state RxBleConnectionState{DISCONNECTED}
12-09 21:23:46.897 8992-8992/appName D/Peripheral Manager: setConnectionState: Set e0:cf:8d:98:69:6a connection state to Disconnected
12-09 21:23:46.898 8992-8992/appName E/PeripheralManager: ### sendDisconnectNotification: mid = 2698601

>>> ATTEMPT RECONNECT HERE <<<<
12-09 21:23:46.904 8992-8992/appName D/PeripheralManager: RxBleConnect: connecting to sensor...., auto connect = true
12-09 21:23:46.915 8992-9004/appName D/RxBle#Radio:   QUEUED RxBleRadioOperationDisconnect(250971465)
12-09 21:23:46.916 8992-9070/appName D/RxBle#Radio:  STARTED RxBleRadioOperationDisconnect(250971465)
12-09 21:23:46.922 8992-9004/appName D/BluetoothGatt: setCharacteristicNotification() - uuid: f8c00003-159f-11e6-92f5-0002a5d5c51b enable: false
12-09 21:23:46.928 8992-9004/appName D/RxBle#Radio:   QUEUED RxBleRadioOperationDescriptorWrite(49261423)
12-09 21:23:47.306 8992-8992/appName D/RxBle#Radio:   QUEUED RxBleRadioOperationConnect(200794900)
12-09 21:23:47.316 8992-8992/appName D/PeripheralManager: onConnectionStateChange: new state RxBleConnectionState{CONNECTING}
12-09 21:23:47.316 8992-8992/appName D/Peripheral Manager: setConnectionState: Set e0:cf:8d:98:69:6a connection state to Connecting…
12-09 21:23:47.340 8992-8992/appName D/BluetoothManager: getConnectionState()
12-09 21:23:47.340 8992-8992/appName D/BluetoothManager: getConnectedDevices
12-09 21:23:47.347 8992-9070/appName D/RxBle#Radio: FINISHED RxBleRadioOperationDisconnect(250971465)
12-09 21:23:47.348 8992-9070/appName D/RxBle#Radio:  STARTED RxBleRadioOperationDescriptorWrite(49261423)
12-09 21:23:47.348 8992-8992/appName D/PeripheralManager: rxBleConnection doOnError: BleGattException{status=8, bleGattOperation=BleGattOperation{description='CONNECTION_STATE'}}
12-09 21:23:47.355 8992-8992/appName D/PeripheralManager: observeConnectionStateChanges FINISHED
12-09 21:23:47.355 8992-8992/appName D/PeripheralManager: rxBleConnection doOnError: BleGattException{status=8, bleGattOperation=BleGattOperation{description='CONNECTION_STATE'}}

Спасибо!

2-е РЕДАКТИРОВАНИЕ:

Код для употребления

private void RxBleOnConnectionReceived (RxBleDeviceServices services) {// обнаруживаем службы

    connectionsCount ++;

    Log.d(TAG, "RxBleOnConnectionReceived: Discovered services");


    setConnectionState(SensorConnectionState.Connected);

    try {



    connectionSubscription = connectionObservable
            .flatMap(rxBleConnection -> rxBleConnection.setupNotification(BluetoothLeUart.RX_UUID))
            .doOnError(throwable -> {
                Log.d(TAG, "RxBleOnConnectionReceived setupNotification doOnError: " + throwable);
                Disconnect(); 
            })
            .doOnNext(notificationObservable -> {
                // Notification has been set up
            })
            .flatMap(notificationObservable -> notificationObservable) // <-- Notification has been set up, now observe value changes.
            .observeOn(AndroidSchedulers.mainThread())
            .doOnError(throwable -> {
                Log.d(TAG, "RxBleOnConnectionReceived doOnError: " + throwable);
            })
            .subscribe(
                    bytes -> {
                        // Given characteristic has been changes, here is the value.
                    processReceivedMessage(bytes);

                    },
                    throwable -> {
                        /*handle throwable*/

                        Log.e(TAG, "RxBleOnConnectionReceived: processReceivedMessage: " + throwable );
                    }
            );

person seano    schedule 01.12.2016    source источник
comment
привет, я столкнулся с этим исключением прямо сейчас, уже более двух дней, ваша помощь очень ценится. Вы можете отправить фрагмент или код.   -  person prasanthMurugan    schedule 06.02.2017


Ответы (1)


Вы задали несколько вопросов:

  • Какой услугой пользоваться, когда телефон переходит в спящий режим?

Хороший вопрос о уже доступном stackoverflow. Например, здесь: Как работает режим дремоты влияют на фоновые / передние службы с частичной / полной блокировкой пробуждения или без нее? На странице github плагина Cordova также есть проблема с использованием BLE во время дремоты: https://github.com/thaliproject/Thali_CordovaPlugin/issues/413

  • RxAndroidBle должен ли автоматически переподключаться, если устройство теряет соединение?

Нет. После завершения соединения (если оно было запущено с использованием autoconnect = true или false) его необходимо восстановить, снова вызвав RxBleDevice.establishConnection. Из описания библиотеки:

Автоматическое подключение

(...)

На первый взгляд концепция автоматического подключения может ввести в заблуждение. Если для флага autoconnect установлено значение false, соединение завершится ошибкой, если устройство BLE не рекламирует при вызове метода RxBleDevice # installConnection. Время ожидания от платформы к платформе, после которого возникает ошибка, различается, но в целом это скорее десятки секунд, чем отдельные секунды.

Установка флага автоматического подключения в значение true позволяет дождаться, пока устройство BLE не станет обнаруживаемым. Экземпляр RxBleConnection не будет отправлен, пока соединение не будет полностью установлено. По опыту он также обрабатывает активацию блокировки пробуждения, поэтому можно с уверенностью предположить, что ваше устройство Android будет активировано после того, как соединение будет установлено, но это не задокументированная функция и может измениться в будущих выпусках системы.

  • Будет ли сканирование или соединение с autoconnect = true позаботиться о повторном подключении?

Трудно понять, что запускает функцию scanForDevices(), но похоже, что она автоматически завершается через 4 секунды. Если сканирование включено и пользователь вызовет scanForDevices(true), сканирование все равно будет остановлено.

person Dariusz Seweryn    schedule 01.12.2016
comment
Большое тебе спасибо. Итак, EstablishConnection постоянно пытается подключиться, пока не найдет это устройство? или он выходит из строя после короткого тайм-аута? Думаю, я постараюсь доложить, если у вас нет результата теста. И да, scanForDevices вызывается после инициализации rxble и запускается каждые 8 ​​секунд в течение 4 секунд. Но я считаю, что когда приложение перейдет в режим глубокого сна, ему ничего не удастся сделать ... - person seano; 01.12.2016
comment
Я отредактировал ответ. Краткая история: autoconnect = false - ›таймаут через 30 секунд, если устройство недоступно, autoconnect = true -› нет таймаута, пока устройство не станет доступным. Отсюда: github.com/thaliproject/Thali_CordovaPlugin/issues/413, о котором вы можете прочитать возможные сценарии с дремотой. По-видимому, это не сильно меняет, если служба работает. - person Dariusz Seweryn; 01.12.2016
comment
Какой ответ? Если я не ответил на ваш вопрос - пожалуйста, поясните мне их или опишите, чего вы хотите достичь. - person Dariusz Seweryn; 09.12.2016
comment
Извините, мой первый пост SO ... Что касается моей проблемы, у меня мгновенный сбой автоподключения .... Мой код для Rxbleconnect приведен выше. Если я установил для параметра autoconnect значение true, первое подключение будет успешным, но затем после первого DISconnect, если я попытаюсь подключиться снова, RxAndroidBle немедленно отключается ... похоже, он немедленно входит в часть .doOnUnsubscribe моего вызова installConnection ... Есть идеи, почему? Как мне убедиться, что есть подписчик? Это потому, что я разделил connectionObservable и connectionSubscription на отдельные вызовы? (см. код выше) Спасибо! - person seano; 09.12.2016
comment
Если вы используете подкласс Subscriber для обработки событий, имейте в виду, что они сохраняют состояние. Если один Subscriber получит onCompleted() или onError(), он не будет работать при повторной подписке. Это должен быть новый Subscriber. Во-вторых, Observable, который является результатом RxBleDevice.establishConnection(), предназначен для использования только один раз. После отключения или ошибки потребуется еще один вызов RxBleDevice.establishConnection(). - person Dariusz Seweryn; 10.12.2016
comment
Спасибо за быстрые ответы. Я не использую подкласс подписчика. Я вызываю подписку после того, как выясню, какие услуги предоставляет устройство ... Код см. Во втором редактировании выше ... Моя ситуация очень похожа на ту, что в stackoverflow.com/questions/38902913/ Но я думаю, что я знаю rxjava недостаточно. Хотелось бы, чтобы у этого типа приложения для библиотеки был полный эталонный дизайн ... постоянные подключения к Интернету вещей становятся все более популярными. Я знаю, что это довольно много вопросов, поэтому я не ожидал этого .. - person seano; 10.12.2016
comment
Я подумаю о более сложном примере с поддержанием соединения и обработкой нескольких (асинхронных) событий в течение времени. Каждый вариант использования индивидуален, и без вашего полного знания я не могу помочь. На данный момент я могу только посоветовать вам расширить свои знания о rxJava - это определенно принесет вам пользу. - person Dariusz Seweryn; 13.12.2016