接近警告误报

时间:2016-02-03 18:36:59

标签: android gps geolocation proximity

我在我的应用中设置了接近警报,它可以很好地捕捉到我的位置。但是,我注意到我不应该收到很多警报而且我无法弄明白为什么。

误报的频率与我距离代理警报的距离成反比。如果我将我的接近设置为5公里外,我会每隔一小时得到误报,但如果我将它设置为加拿大北部,我就不会得到误报。

以下是我的日志从5公里外的样子(我的范围设置为100米)

12:25:08 (exited) //This is correct, as I set my mock location away
3:11:45 (enter) //This and the following are all incorrect
3:12:31 (exit)
3:15:45 (enter)
3:15:45 (exit)
3:20:50 (enter)
3:21:10 (exit) 
7:43:13 (enter)
7:43:24 (exit)
8:45:21 (enter)
8:45:49 (exit)
8:54:23 (enter)
8:55:09 (exit)
10:26:07 (enter)
10:26:13 (exit)
10:35:03 (enter)
10:35:14 (exit)
2:00:13 (enter) //I sleep, so phone is not being used from here to end of logs
2:00:32 (exit)
2:04:14 (enter)
2:04:52 (exit)
2:18:16 (enter)
2:19:33 (exit)
2:32:20 (enter)
2:33:10 (exit) 
4:56:15 (enter)
4:56:25 (exit)
6:03:42 (enter)
6:04:04 (exit)
6:56:57 (enter)
6:57:08 (exit)

任何人都可以看到一种模式或怀疑为什么我会得到误报吗?(请参阅底部了解更多可能的线索)

我自然怀疑Prox警报不是很准确,但我没有发现其他人抱怨此事的证据。此外,其他代理警报应用程序(如Road Rooster)在我的设备上没有出现故障。

//This is called once when when initial location is selected, the code for which I have ommitted. 
public void addProximityAlert(double lat, double lng){
    LocationManager lm=(LocationManager) getSystemService(LOCATION_SERVICE);
    SharedPreferences prefs = getApplicationContext().getSharedPreferences(Constants.SHARED_PREFS, Context.MODE_MULTI_PROCESS);
    removeAllProximityAlerts(this);
    float range = (float) prefs.getInt("range", -1);
    if (range < 0){
        prefs.edit().putFloat("range", (float) 50);
        range = 50;
    }
    Intent intent = new Intent(Constants.PROX_INTENT_FILTER);
    int alertId= (int) System.currentTimeMillis();
    PendingIntent pi = PendingIntent.getBroadcast(this, alertId , intent, 0);
    SharedPreferences.Editor editor = prefs.edit();
    editor.putInt("maxAlertId", alertId).commit();
    Util.putDouble(editor, Constants.DEST_LAT, lat);
    Util.putDouble(editor, Constants.DEST_LNG, lng);
    editor.commit();
    lm.addProximityAlert(lat, lng, range, -1, pi);
}

public void removeAllProximityAlerts(Context context) {
    LocationManager lm=(LocationManager) getSystemService(LOCATION_SERVICE);
    SharedPreferences prefs = getApplicationContext().getSharedPreferences(Constants.SHARED_PREFS, Context.MODE_MULTI_PROCESS);
    int maxAlertId = prefs.getInt("maxAlertId", 0);      

    Intent intent = new Intent(Constants.PROX_INTENT_FILTER);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(this , maxAlertId, intent, 0);
    lm.removeProximityAlert(pendingIntent);
}

接收机

public class ProximityReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent arg1) {

    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
    wl.acquire();

    String k = LocationManager.KEY_PROXIMITY_ENTERING;
    boolean state = arg1.getBooleanExtra(k, false);

    String enterOrLeave;
    if (state) {
        //Todo: Enter state
        enterOrLeave="entered";
        updateLastDayRecord("Went to gym");
    } else {
        //Todo: Exit state
        enterOrLeave="exited";
    }
    //Do stuff (ommitted unrelated code)
 }
}

清单

<?xml version="1.0" encoding="utf-8"?>

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:name="GlobalState"
    android:theme="@style/AppTheme" >
    <activity
        android:name=".AllinOneActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name=".IntroductionActivity"
        android:label="@string/intro_label"
        android:parentActivityName=".AllinOneActivity" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".AllinOneActivity" />
    </activity>

    <activity android:name=".MessageBodyActivity"
        android:label="@string/message_label"
        android:parentActivityName=".AllinOneActivity">
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".AllinOneActivity" />
    </activity>


    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />
    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="@string/GOOGLE_API_KEY" />

    <receiver
        android:name=".AlarmManagerBroadcastReceiver"
        android:process=":remote">
    </receiver>

    <receiver
        android:name=".ProximityReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.pipit.agc.agc.ProximityReceiver" />
        </intent-filter>
    </receiver>

    <receiver android:name=".BootReceiver">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
        </intent-filter>
    </receiver>
</application>

bootreceiver只是重置警报管理器。

其他信息

  • 在Nexus 5上测试
  • 始终在预期时收到代理提醒
  • 当接近
  • 时,误报的频率会更高
  • 我正在我的接收器中检查LocationManager的getLastKnownLocation并且它永远不会被更新,尽管我可能会错误地使用它
  • 切换到显式意图(使用registereceiver)时问题仍然存在
  • 即使在选择了一个位置的干净安装后问题仍然存在(暗示多个冲突的警报不是问题)

花了两个周末试图找出这个错误 - 我一直认为它已被修复,几个小时后我会得到另一个误报。

1 个答案:

答案 0 :(得分:3)

接近警报是基于GPS或网络位置的。这两者都有不准确之处。实际上,您在Location对象中传回的精度以米为单位。只有67%的几率你在这个范围内 - 你有1/3的机会在你的范围之外。

轻微不准确的可能性大于大的。乘坐GPS 10米?合理,实际上很常见。离开1公里?如果使用卫星系统发生奇怪的事情,可能会发生,但应该快速纠正自己。离开100公里?除了软件中的错误之外,不会发生。

因此,假设GPS位置偏离5公里的可能性为5%。每分钟更新2个位置,或每小时120个。没有假阳性的几率是.95 ^ 120,或.2%。即使假阳性的可能性只有1%,也就有27%的几率没有一个小时。在使用基于位置的算法时,误报只是您必须要处理的事情。

解决此问题的一种方法是不要通过邻近警报触发您的操作。相反,当接近警报触发请求位置更新并确保它保持在该区域内以进行更新或两次更新时。这会增加延迟,但会减少误报。另请注意,随着您越来越接近目标区域,误报将随着您在该区域所需的不准确度减少而增加,因此更有可能。