Android 接近警报误报

Android 接近警报误报,android,gps,geolocation,proximity,Android,Gps,Geolocation,Proximity,我在我的应用程序中设置了接近警报,它可以很好地捕捉我的位置。然而,我注意到我收到了很多不该收到的警告,我也不知道为什么 误报的频率与我离prox警报的距离成反比。如果我将prox设置为5公里以外,每隔一小时就会出现误报,但如果我将prox设置为加拿大北部,则不会出现误报 这是我的日志在5公里外的样子(我的范围设置为100米) 有人能看到模式或怀疑我为什么会出现误报吗?(更多可能的线索,请参见底部) 我自然怀疑Prox警报不是很准确,但我没有发现其他人对此抱怨的证据。此外,我的设备上的其他prox

我在我的应用程序中设置了接近警报,它可以很好地捕捉我的位置。然而,我注意到我收到了很多不该收到的警告,我也不知道为什么

误报的频率与我离prox警报的距离成反比。如果我将prox设置为5公里以外,每隔一小时就会出现误报,但如果我将prox设置为加拿大北部,则不会出现误报

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

有人能看到模式或怀疑我为什么会出现误报吗?(更多可能的线索,请参见底部)

我自然怀疑Prox警报不是很准确,但我没有发现其他人对此抱怨的证据。此外,我的设备上的其他prox alert应用程序(如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);
}
清单

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


引导接收器只是重置报警管理器

附加信息

  • 在Nexus5上测试
  • 总是在需要时接收prox警报
  • 当距离较近时,误报的频率较高
  • 我正在我的接收器中检查LocationManager的getLastKnownLocation,它从未被更新,尽管我可能使用不正确
  • 切换到显式意图(使用RegisterReceiver)时问题仍然存在
  • 即使在只选择了一个位置的干净安装之后,问题仍然存在(这意味着多个冲突警报不是问题)

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

接近警报基于GPS或网络位置。这两种方法都不准确。事实上,在定位对象中传回的精度以米为单位。只有67%的几率你在这个范围内,有1/3的几率你在这个范围之外

轻微的误差远比大的误差大。用GPS离地球10米远?合理,事实上是普遍的。离这里1公里?如果卫星系统发生了奇怪的事情,可能会发生,但应该会很快自我纠正。距离100公里?这是不会发生的,除了软件中的一个bug

因此,假设GPS定位偏离5公里的几率为5%。每分钟更新2个位置,或每小时更新120个位置。没有假阳性的几率为.95^120,或.2%。即使只有1%的几率出现假阳性,也有27%的几率有一个小时没有假阳性。在执行基于位置的算法时,误报只是必须处理的问题


解决这一问题的一种方法是,不要通过近距离警报触发您的操作。相反,当近距离警报触发时,请请求位置更新,并确保其停留在该区域内进行一两次更新。这会增加延迟,但会减少误报。还要注意的是,当您越来越接近目标区域时,误报率会随着将您放入该区域所需的不准确度的降低而增加,因此,误报的可能性更大。

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

轻微的误差远比大的误差大。用GPS离地球10米远?合理,事实上是普遍的。离这里1公里?如果卫星系统发生了奇怪的事情,可能会发生,但应该会很快自我纠正。距离100公里?这是不会发生的,除了软件中的一个bug

因此,假设GPS定位偏离5公里的几率为5%。每分钟更新2个位置,或每小时更新120个位置。没有假阳性的几率为.95^120,或.2%。即使只有1%的几率出现假阳性,也有27%的几率有一个小时没有假阳性。在执行基于位置的算法时,误报只是必须处理的问题


解决这一问题的一种方法是,不要通过近距离警报触发您的操作。相反,当近距离警报触发时,请请求位置更新,并确保其停留在该区域内进行一两次更新。这会增加延迟,但会减少误报。还要注意的是,当您越来越接近目标区域时,误报率会随着将您放入该区域所需的不准确度的降低而增加,因此这种情况更可能发生。

感谢您的回复,这正是我希望听到的。您提到请求位置更新以验证准确性-这是否会在电池方面产生重大成本?我想另一种方法是等待2-3分钟,看看GPS是否能自我修正。刚刚看到你的编辑,这回答了我的最后一个问题,谢谢。如果你一直这么做,它会的。相反,您只能在进入或退出事件后请求它,并在完成后将其关闭。那么,只有当你处于边缘并不断打开它时,这才有意义。此外,由于已经为“倾向性警报”启用了定位功能,因此,如果系统使用网络,并且你使用gpsThanks进行回复,则只会增加电池电量,这是我希望听到的。您提到请求位置更新以验证准确性-这是否会在电池方面产生重大成本?我想另一种方法是等待2-3分钟,看看GPS是否能自我修正。刚刚看到你的编辑,这回答了我的最后一个问题,谢谢。如果你一直这么做,它会的。相反,您只能在进入或退出事件后请求它,并在完成后将其关闭。那就只有签字了
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>