addProximityAlert无法按预期工作。

3

iOS SDK拥有出色的区域监控功能。我需要在Android中实现类似的功能,我认为我们有两种选择:Geofencing和LocationManager。

Geofencing有非常整洁的示例和错误处理,因此我更喜欢使用LocationManager。在LocationManager中一切都很好,除了一个问题。如果将您当前的位置添加为ProximityAlert,则会立即触发“ENTERING”,但这是我的当前位置,并不意味着我已进入该区域。因此,如果我在该区域内(即使我没有移动),每次启动应用程序时它都会触发“ENTERING”。

我该如何解决这个问题并仅在用户真正进入该区域时触发事件?

以下是我为我的位置添加PendingIntents的方式:

    LocationManager locationManager =  (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);

    for(Place p : places)
    {
        Log.e("location", p.location);

        Bundle extras = new Bundle();
        extras.putString("name", p.displayName);
        extras.putString("id", p.id);
        Intent intent = new Intent(CommandTypes.PROX_ALERT_INTENT);
        intent.putExtra(CommandTypes.PROX_ALERT_INTENT, extras);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,Integer.parseInt(p.id), intent,PendingIntent.FLAG_CANCEL_CURRENT);
        float radius = 50f;
        locationManager.addProximityAlert(p.lat,
                p.lon, radius, 1000000, pendingIntent);

    }       

接收器

public class ProximityReceiver extends BroadcastReceiver {

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

    final String key = LocationManager.KEY_PROXIMITY_ENTERING;
    final Boolean entering = intent.getBooleanExtra(key, false);

    Bundle b = intent.getBundleExtra(CommandTypes.PROX_ALERT_INTENT);
    String id = b.getString("id");
    Log.e("here" + id, "here");

    if (entering) {
        Log.e(TAG,"entering");
    } else {
        Log.e(TAG,"leaving");
    }
} 

清单文件

   <receiver android:name=".ProximityReceiver">
        <intent-filter>
            <action android:name="ACTION_PROXIMITY_ALERT" />
        </intent-filter>            
    </receiver>

非常感谢。
PS:iOS没有这个问题,并且他们的文档已经解释了。
在授权应用程序注册后,地理区域的监视将立即开始。但是,不要期望立即收到事件。只有边界穿越才会生成事件。因此,如果在注册时用户的位置已经在区域内,位置管理器不会自动生成事件。相反,您的应用程序必须等待用户越过区域边界,然后才会生成并发送事件到委托。话虽如此,您可以使用CLLocationManager类的requestStateForRegion:方法检查用户是否已经在区域的边界内。

如果您查看源代码locationManager.addProximity(..),那么您将会看到这个方法与地理围栏一起工作。 - Harco
1个回答

3

编辑: 自从我写这篇文章以来,地理围栏API新增了一项“setInitialTrigger”函数,可以解决这个问题:

https://developers.google.com/android/reference/com/google/android/gms/location/GeofencingRequest.Builder#setInitialTrigger%28int%29

很遗憾,这是一个麻烦事,也是Android和IOS地理围栏有所不同的主要点之一。

如果Android知道你之前在围栏外面,或者在围栏内部添加了该围栏,那么当你在围栏内部时,它会发送警报。

我的解决方法是在广播接收器中设置一个“宽限期”。基本上,当我创建地理围栏时,我将其创建时间存储在SharedPreferences中,并在onReceive中与该值进行比较。

通过这样做,任何“立即”触发都将被过滤掉。也许对于其他人来说3分钟太长了,但对我来说可以根据应用程序中如何使用地理围栏而有效地工作。

private static final Long MIN_PROXALERT_INTERVAL = 18000l; // 3 mins in milliseconds

...

long geofenceCreationTime = session.getPrefs().getCurrentGeofenceCreation();
long elapsedSinceCreation = now - geofenceCreationTime;
if(elapsedSinceCreation < CREATIONTIME_GRACE_PERIOD){
        if (ApplicationSession.DEBUG) {
            Log.d(TAG, "elapsedSinceCreation;"+elapsedSinceCreation+";less than;"+CREATIONTIME_GRACE_PERIOD+";exiting");
        }
        return;

    }

希望你能明白我想表达的意思。

希望这有所帮助。


只需在待定意图中添加一个 SystemClock.elapsedRealtime(),然后在接收广播时与之比较即可。无需存储为首选项。 - ballzak
我认为可能有一个原因。如果手机重新启动,您想要重新创建地理围栏,那么您将希望跟踪地理围栏的原始创建时间,以便您可以设置重新创建的地理围栏的适当超时时间。假设您希望它为12小时,并且手机在4小时后重新启动。然后,您需要原始创建时间才能将“新”地理围栏的超时时间设置为8小时。这就是为什么我无论如何都将其存储在首选项中的原因。 - Mathias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接