Маяки didEnterRegion и didExitRegion неоднократно вызывались

Я пытаюсь уведомить пользователя, когда пользователь входит в определенный регион, а также когда пользователь выходит из региона. Это то, что я сделал до сих пор. Раньше я использовал метод rangeNotifier (didBeaconsEnterRange), чтобы уведомлять пользователя, когда он/она входит в регион, но тогда этот метод вызывался каждую секунду, поэтому я перенес логику уведомления в метод класса monitorNotifier (didEnterRegion).

Мой класс приложения расширяет BootStrapNotifier, и я устанавливаю scanPeriod на 2000 секунд вместо 1100 секунд по умолчанию, потому что я получаю уведомления о входе и выходе слишком быстро, даже когда маяк находится в пределах досягаемости. Ранее я даже увеличил период ожидания с 10000 мс до 20000 мс, чтобы активировать выход, когда маяк не запускает сигналы в течение периода ожидания.

Фрагмент кода для класса myapplication

BeaconManager beaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
    beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(LAYOUT_HERE));
    beaconManager.setForegroundScanPeriod(2000l);
    beaconManager.setBackgroundBetweenScanPeriod(1100l);
    //beaconManager.setBackgroundScanPeriod(5000l);
    beaconManager.setDebug(true);

    Log.d(TAG, "setting up background monitoring for beacons and power saving");
    // wake up the app when a beacon is seen
    mRegion = new Region("myRangingUniqueId",
            null, null, null);
    setRegionAgain();

Метод SetRegionAgain

if(SharedPrefs.getString(SharedPrefs.iBEACON_ID, "").trim().length() > 0) {
        if(SharedPrefs.getString(SharedPrefs.iBEACON_ID, "").trim().length() > 0 ) {
            try {
                mRegion = new Region("myRangingUniqueId",
                        Identifier.parse(SharedPrefs.getString(SharedPrefs.iBEACON_ID, "")), 
                        null, null);
            }catch(IllegalArgumentException e) {
                e.printStackTrace();
                mRegion = new Region("myRangingUniqueId",
                        null, null, null);
            }
        }
    }

    regionBootstrap = new RegionBootstrap(this, mRegion);

    // simply constructing this class and holding a reference to it in your custom Application
    // class will automatically cause the BeaconLibrary to save battery whenever the application
    // is not visible.  This reduces bluetooth power usage by about 60%
    backgroundPowerSaver = new BackgroundPowerSaver(this);

У меня есть фоновая служба, которая работает с уведомлением, поэтому она реализует интерфейс BeaconConsumer. Фрагмент кода ниже:

Метод OnStart:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    flagToCheckExit = false;
    mHandler = new Handler();
    beaconManager.bind(this);
    if (beaconManager.isBound(this)) beaconManager.setBackgroundMode(false);
    return Service.START_STICKY;
}

Метод onDestroy:

@Override
public void onDestroy() {
    super.onDestroy();
    try {
        beaconManager.stopMonitoringBeaconsInRegion(CommonUtilities.getRegion());
// this region is the one that i use to monitor (singleton types)
    } catch (RemoteException e) {
        e.printStackTrace();
    }

    beaconManager.unbind(this);
}

Метод onServiceConnected:

@Override
public void onBeaconServiceConnect() {
    beaconManager.setMonitorNotifier(new MonitorNotifier() {

        @Override
        public void didExitRegion(final Region region) {
            LogManager.d(TAG, "didExitRegion %s", region);

            if(SharedPrefs.getString(SharedPrefs.USER_ID, "").trim().length() > 0) {
                flagToCheckExit = true;
// i use this flag to prevent random entry and exit notifications
                mHandler.postDelayed(mRunnable, 20000);
// waiting for 20seconds before firing an exit notification, since an entry notification might get fired immediately after the exit
            }
        }

        @Override
        public void didEnterRegion(Region region) {
            Log.e(TAG,"region id1 >>> " + ((region.getId1() == null) ? "null" : region.getId1().toUuidString()));

            LogManager.d(TAG, "didEnterRegion %s ",region);

            if(!flagToCheckExit) {
                if(SharedPrefs.getString(SharedPrefs.USER_ID, "").trim().length() > 0) {
                    if(region.getId1() != null && 
                            region.getId1().toUuidString().equalsIgnoreCase(SharedPrefs.getString(SharedPrefs.iBEACON_ID, ""))) {
                        if(!SharedPrefs.getBoolean(SharedPrefs.IS_ENTRY_LOG_CALLED, false)) {
                            String entryRange = getAppContext().getString(R.string.entered_beacon_region);
                    CommonUtilities.sendNotification(MonitoringAltBeaconService.this,entryRange,1);
                        }
                    }
                }
            }else {
                // invalidate the handler
                // stop all operations of the handler
                // we do this to prevent an exit getting called since entry has been called immediately.
                mHandler.removeCallbacks(mRunnable);
            }
        }

        @Override
        public void didDetermineStateForRegion(int state, Region region) {
            LogManager.d(TAG, "didDetermineStateForRegion %s ",region);
        }
    });

    startMonitoring();
}

Метод startMonitoring:

private void startMonitoring() {
    try {
        if(SharedPrefs.getString(SharedPrefs.iBEACON_ID, "").trim().length() > 0 ) {
            try {
                beaconManager.startMonitoringBeaconsInRegion(CommonUtilities.getRegion());
            }catch(IllegalArgumentException e) {
                e.printStackTrace();

                beaconManager.startMonitoringBeaconsInRegion(CommonUtilities.getRegion());
            }
        }
    } catch (RemoteException e) {   }
}

исполняемый поток:

Runnable mRunnable = new Runnable() {
    @Override
    public void run() {
        SharedPrefs.putBoolean(SharedPrefs.IS_ENTRY_LOG_CALLED, false);
        SharedPrefs.putBoolean(SharedPrefs.IS_EXIT_LOG_CALLED, true);

        String exitedRange = getAppContext().getString(R.string.exited_beacon_region);
        CommonUtilities.sendNotification(MonitoringAltBeaconService.this,exitedRange,2);
        LogManager.d(TAG, "exit called");
        flagToCheckExit = false;
    }
};

При этом наблюдается странное поведение, есть несколько журналов входа и выхода, которые я получаю, даже когда устройство маяка находится в пределах досягаемости, я получаю выход. Я попытался обойти уведомление о выходе, но, похоже, это не работает с логикой (исправлением) выше.

Журнал:

03-19 18:00:25.866: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:00:25.867: D/MonitoringAltBeaconService(22795): didExitRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
03-19 18:00:26.470: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 

03-19 18:00:26.477: D/MonitoringAltBeaconService(22795): didEnterRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 

03-19 18:00:48.076: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:00:48.076: D/MonitoringAltBeaconService(22795): didExitRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null

03-19 18:00:51.275: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:00:51.282: D/MonitoringAltBeaconService(22795): didEnterRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:01:10.269: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
03-19 18:01:10.269: D/MonitoringAltBeaconService(22795): didExitRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
03-19 18:01:15.876: D/MonitoringAltBeaconService(22795): didDetermineStateForRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 
03-19 18:01:15.883: D/MonitoringAltBeaconService(22795): didEnterRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null 

Я использую Эйприл Бикон. Приложение, над которым я работаю, задерживается, потому что маяки неправильно генерируют уведомления. Пожалуйста помогите.

ИЗМЕНИТЬ:

устройство, которое я использую, если Motorolla g2, этот сценарий происходит как в версии kitkat, так и в версии леденца. И Wi-Fi включен, я предпочитаю, чтобы он был включен, поскольку при определении входа и выхода задействованы вызовы веб-сервиса. В реальном времени не рекомендуется просить пользователей выключить Wi-Fi :(..

Я использую библиотеку android-beacon-library здесь, и я Боюсь, я не знаю, на какой частоте апрельский маяк посылает сигналы.

РЕДАКТИРОВАТЬ 2:

Журнал 1 можно найти здесь

Журнал 2 можно найти здесь

ИЗМЕНИТЬ 3

журнал при выключенном Wi-Fi Я заметил, что получил выход, даже когда маяк был включен диапазон И я открыл приложение для поиска, и оно показало, что маяков нет (см. Скриншот). я вынул аккумулятор и вставил их обратно, он получил маяк, и мое приложение тоже. (но в реальной жизни я уверен, что батареи не будут подделаны)

Если не обнаруженоПосле извлечения батарей


person Rat-a-tat-a-tat Ratatouille    schedule 20.03.2015    source источник
comment
Я понимаю, что не хочу отключать Wi-Fi, но не могли бы вы попробовать это в качестве шага по устранению неполадок и сообщить нам, если это имеет значение? Это поможет отследить проблему.   -  person davidgyoung    schedule 20.03.2015


Ответы (3)


Ваша конфигурация кажется правильной, но есть небольшой недостаток. Вы должны были установить обе конфигурации сканирования переднего плана:

beaconManager.setForegroundScanPeriod(2000l);
beaconManager.setForegroundBetweenScanPeriod(1100l);
//Update default time with the new one
beaconManager.updateScanPeriods();

и/или конфигурации фонового сканирования:

beaconManager.setBackgroundScanPeriod(2000l);
beaconManager.setBackgroundBetweenScanPeriod(1100l);
//Update default time with the new one
beaconManager.updateScanPeriods();

Кроме того, знаете ли вы частоту рекламы маяка? Вы сказали, что увеличили период сканирования до 20 секунд, и ничего не изменилось, но частота была бы полезна для нас, чтобы помочь вам.

Кстати, можете ли вы также поделиться выходными данными AltBeacon logcat? Кроме того, какое у вас устройство и модель? И какая версия Android работает? И какую версию библиотеки AltBeacon вы используете?

Если на вашем устройстве работает Lollipop, попробуйте следующую строку и поделитесь с нами результатами:

BeaconManager.setAndroidLScanningDisabled(true);

Кроме того, попробуйте отключить Wi-Fi, если он включен, потому что на некоторых устройствах он мешает сканированию Bluetooth.

Кстати, извините, это больше похоже на комментарий, чем на ответ, но это тоже было долго для комментария :).

person Furkan Varol    schedule 20.03.2015
comment
Пожалуйста, проверьте редактирование в вопросе. Мне потребуется некоторое время, прежде чем я смогу опубликовать журналы AltBeacon. Я просто пропустил получение журналов. - person Rat-a-tat-a-tat Ratatouille; 20.03.2015
comment
Можете ли вы проверить с выключенным Wi-Fi? Я знаю, что на самом деле вы не можете предположить, что Wi-Fi выключен или заставить пользователя отключить его, но, по крайней мере, мы можем быть в этом уверены. Кстати, на самом деле я спрашивал, какую версию библиотеки AltBeacon вы используете. Извините за недопонимание. - person Furkan Varol; 20.03.2015
comment
привет, а где взять версию? в папках его нет. я скачал неделю назад. - person Rat-a-tat-a-tat Ratatouille; 20.03.2015
comment
привет, я добавил журналы, журналы alt beacon, если это поможет. - person Rat-a-tat-a-tat Ratatouille; 20.03.2015
comment
Эти ссылки выглядят мертвыми :). Пишет, что эта паста была удалена!. Кстати, вы запускали справочное приложение на своем устройстве? Если вы этого не сделали, пожалуйста, протестируйте его, чтобы мы могли понять, есть ли проблема с библиотекой или вашим кодом. Также проверьте с помощью Найти приложение. - person Furkan Varol; 20.03.2015
comment
Для этого варианта использования я думаю, что период между сканированием должен быть 0l. - person davidgyoung; 20.03.2015
comment
Попробуйте устранить те же проблемы с отключенным Wi-Fi .. также, пожалуйста, найдите исправления в ссылках на журнал. и я тоже скачаю приложение и проверю. - person Rat-a-tat-a-tat Ratatouille; 20.03.2015
comment
@davidgyoung, Furkan - iv добавил изображения и журнал также при выключенном Wi-Fi. я получил выход, даже когда маяк был в пределах досягаемости: S .. когда Wi-Fi выключен. - person Rat-a-tat-a-tat Ratatouille; 20.03.2015

Проблема заключается в сочетании нечасто рекламирующего маяка и слишком короткого пользовательского интервала фонового сканирования.

Похоже, что маяк рекламирует только один раз каждые 2 секунды, потому что это самое близкое время, которое я когда-либо видел в журнале с двумя последовательными отметками времени обнаружения. Это проблема низкой частоты передачи, которая усугубляется пользовательскими настройками.

Для правильной работы библиотеки период фонового сканирования должен быть как минимум в 5 раз больше периода передачи маяка. Это связано с тем, что не все пакеты Bluetooth принимаются из-за радиопомех. Наличие интервала, в 5 раз превышающего период передачи, означает, что существует 5 шансов получить пакет в каждом цикле фонового сканирования, что делает очень маловероятным, что библиотека пропустит один.

В настройках библиотеки по умолчанию установлен период фонового сканирования 10 секунд, что должно быть достаточно, чтобы дать очень высокую вероятность обнаружения даже маяка, передающего только один раз в 2 секунды, и сделать неверные выходы из области очень и очень редкими.

Рекомендации:

  1. Измените период фонового сканирования так, чтобы он составлял не менее 10 секунд по умолчанию. Для экономии заряда батареи период между сканированиями, вероятно, также должен быть больше. хорошая причина, чтобы сделать его короче. Если вы по-прежнему получаете события выхода, увеличьте период фонового сканирования еще больше.

  2. Используйте различные маяки, которые рекламируют чаще. Хотя вы должны иметь возможность заставить библиотеку работать с этими маяками, вы не будете получать обновления так часто, а такие приложения, как Locate, будут периодически показывать пропадания при обнаружении. Если вы выполняете оценку расстояния в своем приложении, вам нужны маяки, передающие на частоте 10 Гц или выше. Если вы не выполняете оценку расстояния в своем приложении, вы все равно должны использовать маяки, которые передают с частотой 1 Гц или выше, иначе у вас будет больше шансов столкнуться с подобными проблемами.

Как я узнаю, что это проблема?

Как видно из фрагментов лога ниже, некорректный выход из региона происходит в 15:50:52, так как с момента предыдущего обнаружения прошло 10 секунд. Любой 10-секундный период без обнаружения вызовет событие выхода из области при следующей остановке цикла сканирования. Таким образом, вы должны быть очень уверены, что цикл сканирования достаточно длинный, чтобы захватить передачу маяка. С пользовательскими настройками отсутствие обнаружения в трех последующих циклах сканирования приведет к выходу из региона.

03-26 15:49:49.533: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:49:55.567: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:01.624: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:08.898: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:11.315: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:17.380: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:21.010: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:26.440: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:30.066: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:33.108: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:36.120: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:39.745: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:41.573: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7

03-26 15:50:52.415: D/MonitorState(28596): We are newly outside the region because the lastSeenTime of 1427365241573 was 10841 seconds ago, and that is over the expiration duration of 10000
03-26 15:50:52.415: D/BeaconService(28596): found a monitor that expired: id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
03-26 15:50:52.415: D/Callback(28596): attempting callback via intent: ComponentInfo{com.credencys.mycarline/org.altbeacon.beacon.BeaconIntentProcessor}

03-26 15:50:54.879: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:50:56.705: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:51:00.940: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:51:03.348: D/BeaconService(28596): beacon detected : id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: 1 id3: 7
03-26 15:51:03.349: D/BeaconService(28596): looking for ranging region matches for this beacon
03-26 15:51:03.842: D/CycledLeScanner(28596): Waiting to stop scan cycle for another 1000 milliseconds
03-26 15:51:04.730: D/MonitoringAltBeaconService(28596): didExitRegion id1: cbb7c628-a321-4cf6-934d-37dbfa335735 id2: null id3: null
person davidgyoung    schedule 21.03.2015
comment
сэр, я немного запутался. BootsrapNotifier, реализовать это в классе приложения или в моей службе? - person Rat-a-tat-a-tat Ratatouille; 07.04.2015
comment
BootsrapNotifier предназначен для реализации пользовательским классом приложения. - person davidgyoung; 07.04.2015
comment
поэтому, если я создам регион в классе приложения, а затем создам регион с определенным uuid после входа в систему, регион в классе приложения будет переопределен? Кроме того, будет ли служба получать вызов didEnter или класс приложения будет принимать вызов didEnter? - person Rat-a-tat-a-tat Ratatouille; 08.04.2015
comment
Если вы используете BootstrapNotifier, все обратные вызовы, включая didEnter, будут отправлены в класс приложения. Вы можете изменить регионы в любое время с помощью вызовов startMonitoringBeaconsInRegion и stopMonitoringBeaconsInRegion. - person davidgyoung; 08.04.2015
comment
Итак, я мог бы обойти внедрение уведомителя начальной загрузки? и просто реализовать BeaconConsumer в моем сервисе? - person Rat-a-tat-a-tat Ratatouille; 08.04.2015
comment
Да, это верный вариант. Избавьтесь от BootstrapNotifier в своем приложении и создайте службу, реализующую BeaconConsumer. - person davidgyoung; 08.04.2015
comment
я пытался это сделать, но потом я не получил тех журналов о том, что идет сканирование, и найден маяк, и все такое :( поэтому я вернулся к старому коду, так как мне нужно было сделать сборку как можно скорее .. - person Rat-a-tat-a-tat Ratatouille; 09.04.2015

EDIT: после просмотра журналов я отправил другой ответ, который лучше отвечает на вопрос. Посмотрите этот ответ.

Из двух опубликованных журналов я заметил, что библиотека сообщает, что приложение находится в фоновом режиме и использует API-интерфейсы Android L. Это заставляет их использовать обнаружения с «малой задержкой»:

03-26 15:47:21.647: D/CycledLeScannerForLollipop(28596): This is Android L. Doing a filtered scan for the background.

Обнаружения с малой задержкой экономят энергию, но задерживаются на 5 секунд и более. Это прекрасно работает для фоновых операций, но не предназначено для операций переднего плана и должно использоваться с интервалами сканирования по умолчанию. Вы никогда не должны устанавливать ненулевой интервал между сканированиями при использовании этих API Andorid L, иначе вы можете получить выходы, как вы описываете.

Если журналы неверно сообщают о том, что ваше приложение работает в фоновом режиме, возможно, что-то не так с настройкой файла BackgroundPowerSaver.

Вы также можете попробовать отключить API-интерфейсы Android L и использовать более старые API-интерфейсы сканирования 4.x, чтобы посмотреть, работает ли это лучше для вашего варианта использования. Если вы сделаете это, я бы также удалил все специальные настройки интервала сканирования, чтобы не усложнять вашу конфигурацию:

beaconManager.setAndroidLScanningDisabled(true)

Вам нужно будет поместить эту строку в onCreate вашего класса приложения, прежде чем выполнять любую другую обработку маяка.

person davidgyoung    schedule 20.03.2015
comment
Сэр, да, это правда, приложение работает в фоновом режиме, так как это тоже один из тестовых случаев, поэтому журнал не сообщает о чем-либо неправильном. :) .. You should never set a non-zero between scan interval when using these Andorid L APIs, otherwise you may get exits like you describe - относится ли это к фоновому сканированию, если я установлю нулевой интервал, это разрядит батарею? - person Rat-a-tat-a-tat Ratatouille; 21.03.2015
comment
Извините, пожалуйста, проигнорируйте мое заявление о ненулевом интервале между проверками — это относится только к предварительной версии поддержки Android L. Пожалуйста, смотрите мой другой ответ. - person davidgyoung; 21.03.2015