我需要在他到达指定地点时通知用户。我为此使用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的服务以提高地理围栏精度。当用户刚进入时 - 禁用位置服务。
答案 0 :(得分:3)
问题在于,当您的手机处于深度睡眠状态时,它无法准确更新位置。更新位置的最准确方法是GPS,这也是电池密集程度最高的。更新您的位置的其他方法(例如使用蜂窝网络)将消耗更少的电池,但也不太准确。默认情况下,地理围栏希望在发送意图之前确定您处于地理围栏中。在深度睡眠时很难获得这种准确性,因为手机无法获得准确的位置数据。
当您解锁手机并使用位置感知应用时,地理围栏立即触发的原因是该应用会更新您的地理围栏所看到的LastLocation,然后发送意图。当您的手机处于深度睡眠状态时,该位置不会更新。
对于地理围栏,您还可以调整一些设置以提高响应能力。我看到你已经在使用setLoiteringDelay
,尝试使用不同的值,也许尝试非常小的值,看看会发生什么。您还可以设置setNotificationResponsiveness
的值,其工作方式类似。这样做可以使您的围栏响应更快,但可能会耗费更多的电池寿命。另请阅读setLoiteringDelay和setNotificationResponsiveness的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。