Beacons做了EnterRegion并且didExitRegion一再打电话

时间:2015-03-20 04:48:14

标签: android bluetooth-lowenergy ibeacon-android altbeacon android-ibeacon

我试图在用户输入定义的区域时以及用户退出该区域时通知用户。这就是我到目前为止所做的。我曾经使用rangeNotifier方法(didBeaconsEnterRange)来通知用户他/她进入一个区域,但是这个方法每隔1秒就被调用一次,所以我将通知逻辑移到了monitorNotifier类(didEnterRegion)方法。

我的应用程序类扩展了BootStrapNotifier,我将scanPeriod设置为2000s而不是默认的1100l秒,因为我似乎收到退出和进入通知的方式太快,即使信标在范围内。早些时候我甚至将超时时间从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 

我正在使用AprilBeacon。我正在处理的应用程序被搁置,因为信标不会正确生成通知。请协助。

修改

我使用的设备如果是Motorolla g2,这种情况同时发生在kitkat和棒棒糖版本中。 Wifi打开,我更喜欢它,因为当确定一个入口退出时,涉及到web服务调用。实时,不鼓励用户切换他们的wifi :( ..

我使用的库是android-beacon-library here,我恐怕不知道4月信标发出信号的频率。

编辑2:

可以找到日志1 here

可以找到日志2 here

编辑3

log when wifi is switched off 我注意到即使灯塔在范围内,我也确实退出了 我打开了定位应用程序,它显示没有信标(见截图)。我取下了电池并将它们放回去了它的灯塔,我的应用也是如此。 (但在现实生活中,我确信电池不会被篡改)

When not detected After removing the batteries

3 个答案:

答案 0 :(得分:1)

您的配置似乎有效但有一点缺陷。你应该设置两个前景扫描配置:

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);

另外,如果打开了WiFi,请尝试将其打开,因为在某些设备中它会干扰蓝牙扫描。

顺便说一句,对不起,这更像是评论而不是答案,但也是为了评论:。

答案 1 :(得分:1)

问题是不经常广告信标和自定义背景扫描间隔太短的组合。

似乎信标只是每2秒发布一次,因为这是我在日志中看到的最接近的两个检测时间戳。这种低传输频率是有问题的,并且由于自定义设置而加剧。

为了正确操作库,后台扫描周期必须至少是信标传输周期的5倍。这是因为并非由于无线电噪声而接收到所有蓝牙分组。具有传输周期的5倍的间隔意味着在每个后台扫描周期中有5次机会接收分组,使得库不太可能错过一个。

默认库设置将后台扫描周期设置为10秒,这应该足以提供非常高的概率来检测即使每2秒仅发送一次信标,并且非常罕见地使不正确的区域退出。

<强>建议:

  1. 将后台扫描周期更改为至少10秒的默认值。为了节省电池,中间扫描周期也可能更长 - 默认值为5分钟是合理的选择,除非你有充分的理由缩短它。如果仍然出现退出事件,请使后台扫描周期更长。

  2. 使用可以更频繁地投放广告的不同信标。虽然您应该能够使图书馆使用这些信标,但您不会经常获得更新,而定位等应用会定期显示检测中的丢失。如果您在应用中进行距离估计,则需要以10Hz或更高频率传输的信标。如果你的应用程序没有进行距离估算,你仍然应该使用以1Hz或更高频率传输的信标,否则你将更有可能遇到这样的问题。

  3. 我怎么知道这是问题?

    从下面的日志摘录中可以看出,在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
    

答案 2 :(得分:0)

编辑:在查看日志后,我提交了一个不同的答案,更好地回答了问题。请看那个答案。

我从两个发布的日志中注意到,该库报告该应用程序处于后台并使用Android L API。这导致他们使用&#34;低延迟&#34;检测:

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

低延迟检测可节省电量,但​​会延迟5秒或更长时间。这适用于后台操作,但它不适用于前台操作,应与默认扫描间隔一起使用。 使用这些Andorid L API时,不应在扫描间隔之间设置非零值,否则您可能会像您描述的那样退出。

如果日志误报您的应用是在后台,那么BackgroundPowerSaver的设置可能有问题。

您也可以尝试禁用Android L API,并使用旧的4.x扫描API查看是否更适合您的用例。如果你这样做,我也会删除任何特殊的扫描间隔设置,以免使配置过于复杂:

beaconManager.setAndroidLScanningDisabled(true)

在进行任何其他信标处理之前,您需要将该行放在应用程序类的onCreate中。