当设备处于深度睡眠(打盹)模式时,地理围栏等待意图发射太晚

时间:2016-09-26 08:08:15

标签: android google-maps location android-geofence

我需要在他到达指定地点时通知用户。我为此使用Geofencing API。当我在Android模拟器上使用模拟位置测试应用程序时一切正常。对于具有模拟位置的真实设备也是如此。但是当我走路并且我的手机处于深度睡眠模式时,Geofence会在5-10分钟后开火。如果我在地理围栏半径内并且我解锁了我的手机,请打开任何使用位置的应用程序我的地理围栏立即触发。 (Android 5.1,Motorolla moto G第1代)

以下是我注册地理围栏的方式:

  public void registerLocation(RegisterAlarmRequestModel data) {
    if (isLocationDetectionAllowed() && isConnected) {
        GeofencingRequest geofencingRequest = prepareGeofencingRequest(prepareGeofence(data));
        PendingIntent pendingIntent = prepareIntent(data.getId());
        PendingResult<Status> result = GeofencingApi.addGeofences(
                googleApiClient, geofencingRequest, pendingIntent);
        Status status = result.await();
        if (status.isSuccess())
            Log.d("Location", "Geofence " + data.getId() + " has been registered");
    }
}

//preparing Geofence Pending Intent which will be triggered 
private PendingIntent prepareIntent(int alarmId) {
    Intent intent = new Intent(context, LocationRingingService.class);
    intent.putExtra(LocationRingingService.KEY_ALARM_ID, alarmId);
    return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}

private GeofencingRequest prepareGeofencingRequest(Geofence geofence) {
    GeofencingRequest.Builder builder = new GeofencingRequest.Builder()
            .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
            .addGeofence(geofence);
    return builder.build();
}

private Geofence prepareGeofence(RegisterAlarmRequestModel data) {
    Geofence geofence = new Geofence.Builder()
            .setRequestId(String.valueOf(data.getId()))
            .setCircularRegion(data.getLatitude(), data.getLongitude(), data.getRadius())
            .setLoiteringDelay(100)
            .setExpirationDuration(Geofence.NEVER_EXPIRE)
            .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
            .build();
    return geofence;
}

对于接收意图,我使用的是IntentService:

@Override
protected void onHandleIntent(Intent intent) {
    Log.d("Location", "accepted intent: " + intent.toString());
    //database request
}

这就是我在清单中注册我的服务的方式:

<service
        android:name=".plugin.delivery.ringing.location.service.LocationRingingService"
        android:enabled="true"
        android:exported="true" />

更新:当用户刚刚进入地理围栏尽可能准确时,我需要赶上。我有一个想法:将半径大于需要的地理围栏登记(例如,如果需要100米半径,则注册地理围栏的半径为200-300米)。当用户进入具有较大半径的Geophence时 - 启动具有位置udating的服务以提高地理围栏精度。当用户刚进入时 - 禁用位置服务。

2 个答案:

答案 0 :(得分:3)

问题在于,当您的手机处于深度睡眠状态时,它无法准确更新位置。更新位置的最准确方法是GPS,这也是电池密集程度最高的。更新您的位置的其他方法(例如使用蜂窝网络)将消耗更少的电池,但也不太准确。默认情况下,地理围栏希望在发送意图之前确定您处于地理围栏中。在深度睡眠时很难获得这种准确性,因为手机无法获得准确的位置数据。

当您解锁手机并使用位置感知应用时,地理围栏立即触发的原因是该应用会更新您的地理围栏所看到的LastLocation,然后发送意图。当您的手机处于深度睡眠状态时,该位置不会更新。

对于地理围栏,您还可以调整一些设置以提高响应能力。我看到你已经在使用setLoiteringDelay,尝试使用不同的值,也许尝试非常小的值,看看会发生什么。您还可以设置setNotificationResponsiveness的值,其工作方式类似。这样做可以使您的围栏响应更快,但可能会耗费更多的电池寿命。另请阅读setLoiteringDelaysetNotificationResponsiveness的API参考。如果您没有,请阅读geofence troubleshooting部分。

您还可以增加地理围栏的大小,尝试将其加倍然后进行测试。由于在深度睡眠时您的位置准确度较低,这将使您的手机更容易确保它在地理围栏内,并且一旦确定它在地理围栏内,它就会发送意图。

我希望这有帮助!

答案 1 :(得分:1)

为了改善它,让我们进行一些检查

1)使用广播接收器轻松触发而不是服务。并使用intent-filter设置优先级。

例如

    <receiver
        android:name=".youpackage.GeoReceiver"
        android:exported="true">
        <intent-filter android:priority="999">
            <action android:name="yourpackage.ACTION_RECEIVE_GEOFENCE" />
        </intent-filter>
    </receiver>

您的未决意图将是:

Intent intent = new Intent("yourpackage.ACTION_RECEIVE_GEOFENCE");
PendingIntent pendingIntent = PendingIntent.getBroadcast(
                youractivity,
                0,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT);

2)当您的GPS进入睡眠模式时,我们需要在创建地理围栏时将其唤醒。创建地理围栏后,您可以开始ping GPS,直到您进入ENTER转换。这必须有助于触发它。

public class GPSService extends Service implements GoogleApiClient.ConnectionCallbacks,    GoogleApiClient.OnConnectionFailedListener, LocationListener {

    GoogleApiClient mGoogleApiClient;
    LocationRequest locationRequest;

    public GPSService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
     // TODO: Return the communication channel to the service.
     throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
      super.onCreate();


     mGoogleApiClient = new GoogleApiClient.Builder(this)
        .addApi(LocationServices.API)
        .addConnectionCallbacks(this)
        .addOnConnectionFailedListener(this)
        .build();

     mGoogleApiClient.connect();
  }

   @Override
   public void onLocationChanged(Location location) {

     Utility.ReadAndWriteData(this, Utility.readFileName(this), "Still Geofence is not triggered!!!");

    }

    @Override
    public void onConnected(Bundle bundle) {

        locationRequest = LocationRequest.create();
      locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        locationRequest.setFastestInterval(1000);
        locationRequest.setInterval(2000);
    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,locationRequest,this);

    }

   @Override
   public void onConnectionFailed(ConnectionResult connectionResult)   {

  }

     @Override
     public void onConnectionSuspended(int i) {

     }

     @Override
     public void onDestroy() {
       super.onDestroy();

        if(mGoogleApiClient.isConnected()) {

     LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);

       }
 } 

当您进入ENTER转换时,不会立即忘记停止此服务或导致电池耗尽。此服务仅用于从睡眠模式唤醒GPS。