这就是我如何添加我的地理位置:
public void setGeofenceRequest(Location location) {
if (geofences == null) {
geofences = new ArrayList<Geofence>();
}
geofences.add(new Geofence.Builder()
.setRequestId("3")
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_EXIT)
.setCircularRegion(
location.getLatitude(), location.getLongitude(), PSLocationService.getInstance(context).kPSGeofencingDistanceMedium)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build());
Intent intent = new Intent(context, ReceiveTransitionsBroadcastReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
if (geofences.size() > 0) {
LocationServices.GeofencingApi.addGeofences(mLocationClient, geofences, pi);
Log.i("", "geof autopilot2 will set geofence for autopilot-3");
}
}这是我的BroadcastReceiver。我应该在那里接收它们:
public class ReceiveTransitionsBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent intent) {
Log.i("","autopilot valid geof on receive transisionts broadcast receiver");
PSMotionService.getInstance(ctx).buildGoogleApiClient();
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
int transitionType = geofencingEvent.getGeofenceTransition();
Location geofenceCenter = PSApplicationClass.getInstance().pref.getGeoCenter(ctx);
if(geofencingEvent.getTriggeringLocation() != null) {
if (geofenceCenter != null) {
Utils.appendLog("GEOFENCE ENTERED ReceiveTransitionsBroadcastReceiver TRIGGERING LOCATION: " + geofencingEvent.getTriggeringLocation().toString() + " / GEOFENCE CENTER: " + geofenceCenter.getLatitude() + ", " + geofenceCenter.getLongitude(), "D", Constants.TRACKER);
} else
Utils.appendLog("GEOFENCE ENTERED ReceiveTransitionsBroadcastReceiver TRIGGERING LOCATION: " + geofencingEvent.getTriggeringLocation().toString(), "D", Constants.TRACKER);
}else Utils.appendLog("GEOFENCE ENTERED ReceiveTransitionsBroadcastReceiver ERROR => TRIGGERING LOCATION NULL", "D", Constants.TRACKER);
if(transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
List<Geofence> triggerList = geofencingEvent.getTriggeringGeofences();
for (Geofence geofence : triggerList) {
Log.i("", "geof is s receive transition broadcast receiver " + transitionType + " GPS zone " + geofence.getRequestId());
if(geofence.getRequestId().contentEquals("3")) {
Log.i("", "geof autopilot2 ENTERED GEOFENCE will start pilot with first location");
Utils.appendLog("GEOFENCE ENTERED ReceiveTransitionsBroadcastReceiver check to see if should start pilot", "T", Constants.TRACKER);
PSLocationService.getInstance(ctx).fastGPS = -1;
PSLocationService.getInstance(ctx).RequestLocationUpdates();
if(PSTrip.getActiveTrip() != null) {
PSLocationService.getInstance(ctx).removeAutoPilotGeofence();
}else PSMotionService.getInstance(ctx).checkinTime = System.currentTimeMillis() / 1000;
}
}
}
}
}现在它通常起作用,但并不总是起作用。我想说的是,只有大约75%的时间它应该工作,地理事件实际上被称为。我觉得我设置地理位置的时间越长,它被调用的可能性就越小。为什么会发生这种情况?当应用程序被垃圾收集器清理时,触发事件是否也被排除了?当发生这种情况时,我怎么做才能使我的地理位置总是被调用呢?
编辑:
这是我的defaultConfig:
defaultConfig {
minSdkVersion 15
targetSdkVersion 23
ndk {
moduleName "ndkVidyoSample"
}
}我从广播接收器变成了IntentService:
public class PSGeofenceTransitionsIntentService extends IntentService {
private static ActivityManager manager;
private static PSGeofenceTransitionsIntentService instance;
private GeofencingClient mGeofencingClient;
Context context;
private PendingIntent mGeofencePendingIntent;
public static boolean isMyServiceRunning(Class<?> serviceClass) {
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
public static PSGeofenceTransitionsIntentService getInstance(Context context) {
if (instance == null) {
// Create the instance
instance = new PSGeofenceTransitionsIntentService(context);
}
if (!isMyServiceRunning(PSGeofenceTransitionsIntentService.class)) {
Intent bindIntent = new Intent(context, PSGeofenceTransitionsIntentService.class);
context.startService(bindIntent);
}
// Return the instance
return instance;
}
public PSGeofenceTransitionsIntentService() {
super("GeofenceTransitionsIntentService");
}
public PSGeofenceTransitionsIntentService(Context context) {
super("GeofenceTransitionsIntentService");
mGeofencingClient = LocationServices.getGeofencingClient(context);
manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
instance = this;
this.context = context;
}
protected void onHandleIntent(Intent intent) {
Log.i("", "autopilot valid geof on receive transisionts broadcast receiver");
PSMotionService.getInstance(context).buildGoogleApiClient();
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
int transitionType = geofencingEvent.getGeofenceTransition();
Location geofenceCenter = PSApplicationClass.getInstance().pref.getGeoCenter(context);
if (geofencingEvent.getTriggeringLocation() != null) {
if (geofenceCenter != null) {
Utils.appendLog("GEOFENCE ENTERED ReceiveTransitionsBroadcastReceiver TRIGGERING LOCATION: " + geofencingEvent.getTriggeringLocation().toString() + " / GEOFENCE CENTER: " + geofenceCenter.getLatitude() + ", " + geofenceCenter.getLongitude(), "D", Constants.TRACKER);
} else
Utils.appendLog("GEOFENCE ENTERED ReceiveTransitionsBroadcastReceiver TRIGGERING LOCATION: " + geofencingEvent.getTriggeringLocation().toString(), "D", Constants.TRACKER);
} else
Utils.appendLog("GEOFENCE ENTERED ReceiveTransitionsBroadcastReceiver ERROR => TRIGGERING LOCATION NULL", "D", Constants.TRACKER);
if (transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
List<Geofence> triggerList = geofencingEvent.getTriggeringGeofences();
for (Geofence geofence : triggerList) {
Log.i("", "geof is s receive transition broadcast receiver " + transitionType + " GPS zone " + geofence.getRequestId());
if (geofence.getRequestId().contentEquals("3")) {
Log.i("", "geof autopilot2 ENTERED GEOFENCE will start pilot with first location");
Utils.appendLog("GEOFENCE ENTERED ReceiveTransitionsBroadcastReceiver check to see if should start pilot", "T", Constants.TRACKER);
PSLocationService.getInstance(context).isLocationRequestsOn = -1;
PSLocationService.getInstance(context).RequestLocationUpdates();
if (PSTrip.getActiveTrip() != null) {
removeAutoPilotGeofence();
} else
PSMotionService.getInstance(context).checkinTime = System.currentTimeMillis() / 1000;
}
}
}
}
public void removeAutoPilotGeofence() {
try {
Log.i("", "autopilot remove autopilot geofence");
List<String> list = new ArrayList<String>();
list.add("3");
if(mGeofencingClient == null)
mGeofencingClient = LocationServices.getGeofencingClient(context);
mGeofencingClient.removeGeofences(list).addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Utils.appendLog("GEOFENCE removeAutoPilotGeofence Success removing geofences!", "I", Constants.TRACKER);
Log.i("", "GEOFENCE removeAutoPilotGeofence Success removing geofences!");
PSApplicationClass.getInstance().pref.setGeoCenterString(context, "-1");
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Utils.appendLog("GEOFENCE removeAutoPilotGeofence FAILURE removing geofences!" + e.getMessage(), "I", Constants.TRACKER);
Log.i("", "GEOFENCE removeAutoPilotGeofence FAILURE removing geofences!" + e.getMessage());
}
});
Utils.appendLog("GEOFENCE: Disabling geofence done removeAutoPilotGeofence", "E", Constants.TRACKER);
} catch (final Exception e) {
if (e.getMessage().contains("GoogleApiClient") && e.getMessage().contains("not connected")) {
PSLocationService.getInstance(context).startLocationClient();
Handler han = new Handler();
han.postDelayed(new Runnable() {
@Override
public void run() {
Utils.appendLog("autopilot2 error will try again", "E", Constants.TRACKER);
removeAutoPilotGeofence();
}
}, 1000);
}
Log.i("", "autopilot2 error replaceFragment autopilot geofence:" + e.getMessage());
Utils.appendLog("autopilot2 error replaceFragment autopilot geofence:" + e.getMessage(), "E", Constants.TRACKER);
}
}
public void setGeofenceRequest(final Location location) {
ArrayList geofences = new ArrayList<>();
geofences.add(new Geofence.Builder()
.setRequestId("3")
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_EXIT)
.setCircularRegion(
location.getLatitude(), location.getLongitude(), PSLocationService.kPSGeofencingDistanceMedium)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build());
//ADDING GEOFENCES
if (geofences.size() > 0) {
if(mGeofencingClient == null)
mGeofencingClient = LocationServices.getGeofencingClient(context);
mGeofencingClient.addGeofences(getGeofencingRequest(location, geofences), getGeofencePendingIntent()).addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
RealmLocation realmLocation = new RealmLocation(location.getLatitude(), location.getLongitude(), location.getTime() / 1000, null, true);
realmLocation.setAccuracy(location.getAccuracy());
realmLocation.setSpeed(location.getSpeed());
PSApplicationClass.getInstance().pref.setGeoCenter(realmLocation, context);
Utils.appendLog("GEOFENCE setGeofenceRequest Success adding geofences!" + location.getLatitude() + " / " + location.getLongitude(), "I", Constants.TRACKER);
Log.i("", "GEOFENCE setGeofenceRequest Success adding geofences! " + location.getLatitude() + " / " + location.getLongitude());
PSLocationService.getInstance(context).stopLocationClient();
PSMotionService.getInstance(context).buildGoogleApiClient();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Utils.appendLog("GEOFENCE setGeofenceRequest FAILURE adding geofences!" + e.getMessage(), "I", Constants.TRACKER);
Log.i("", "GEOFENCE setGeofenceRequest FAILURE adding geofences!" + e.getMessage());
}
});
Log.i("", "geof autopilot2 will set geofence for autopilot-3");
}
}
/**
* Gets a PendingIntent to send with the request to add or remove Geofences. Location Services
* issues the Intent inside this PendingIntent whenever a geofence transition occurs for the
* current list of geofences.
*
* @return A PendingIntent for the IntentService that handles geofence transitions.
*/
private PendingIntent getGeofencePendingIntent() {
// Reuse the PendingIntent if we already have it.
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(context, PSGeofenceTransitionsIntentService.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling
// addGeofences() and removeGeofences().
return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
/**
* Builds and returns a GeofencingRequest. Specifies the list of geofences to be monitored.
* Also specifies how the geofence notifications are initially triggered.
*/
private GeofencingRequest getGeofencingRequest(Location location, ArrayList<Geofence> geofences) {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
// The INITIAL_TRIGGER_ENTER flag indicates that geofencing service should trigger a
// GEOFENCE_TRANSITION_ENTER notification when the geofence is added and if the device
// is already inside that geofence.
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_EXIT);
// Add the geofences to be monitored by geofencing service.
builder.addGeofences(geofences);
// Return a GeofencingRequest.
return builder.build();
}}
我在其中还包含了删除和添加geofence的代码,监听器总是在onSuccess中添加它们。
发布于 2017-10-03 07:07:14
首先,我不会将这段代码放入BroadcastReceiver中。
除了不好的实践之外,该组件可能在代码完成执行之前被关闭。
如果您需要运行可能需要一些时间的代码,请考虑从您的接收器启动服务。否则,在很短的执行时间内,您可以使用IntentService。
通过查看您的代码,我了解到您的地理位置没有按预期工作的两个原因:
1)地学的性质
Geofences主要从WiFi / Cellular检索您的位置,这些数据通常不可用。
我试过一次使用Geofence,但我发现它们非常不准确。我转到LocationManager,使它使用纯GPS定位,它满足了我的期望。
请参阅这个答案,它建议
每隔一段时间轮询GPS硬件,而不对结果做任何事情,您将开始获得更精确的地理位置。
我从来没有尝试过谷歌的FusedLocation API,但我听到人们说它对他们非常有效。
如果您使用LocationManager,您将不得不自己实现“地理映射逻辑”;您可以很容易地使用Location.distanceTo(地点)来实现它。
示例:
final float distanceFromCenter = currentLocation.distanceTo(this.destination);
if (distanceFromCenter <= YOUR_RADIUS_IN_METERS) {
// you are inside your geofence
} 2) CPU不是活动的
地理位置处于活动状态,并不一定意味着您的手机处于清醒状态并进行计算位置检查。
要解决这个问题,您可以从您的ForegroundService启动BroacastReceiver。该服务还应该拥有一个部分WakeLock。这保证:
请注意,如果需要的话,Android可能仍然会扼杀您的服务。
您可以在网上找到很多关于如何从ForegroundService启动BroadcastReceiver、如何保存WakeLock等等的示例.
另外,查看一下新的Android,它给ForegroundService和其他组件带来了一些小的变化。
PS:我开发和应用程序使用了上面提到的所有组件(除了FusedLocation),我非常满意。
编辑:回答OP的问题
好吧,让我们试着在这里下点订单,否则未来的读者可能会很容易被搞糊涂。我将首先回答原始问题和“赏金横幅”中写的内容,然后对OP进行编辑,最后回答OP在评论中提出的问题。
1)原问题
当应用程序被垃圾收集器清理时,触发事件是否也被排除了?
很可能是的。参见这个答案,OP实现了一个在单独进程中运行的服务,以便即使在应用程序被杀死时也会触发geofence。
如果有足够的时间,我需要弄清楚是什么原因导致地勤人员不被打电话的。
有很多理由。看看我最初的答案。
我看到了用服务而不是广播接收器实现geofence逻辑,这会更好吗?
接收者和服务是两种不同的东西。请阅读Android的文档。您可以从BroadcastReceiver启动服务,这通常是“接收”PendingIntents并对其执行某些操作的首选方式。
2)编辑
所有请求都是在一个工作线程上处理的--它们可能需要尽可能长的时间(并且不会阻塞应用程序的主循环),但是一次只处理一个请求。
3)评论
我需要这个工作24/7,因此我不能一直使用位置,因为明显的电池问题。
请阅读Android Oreo后台执行限制。这对你来说可能是个问题。
另外,现在我换了一个intentService,这足以确保它保持清醒吗?
不,正如我所说,您可能需要一个部分WakeLock才能打开CPU。
我是否需要以另一种方式启动它,以保持它的前景?
是。为了启动前台服务,需要调用startForeground(int,通知)
请注意: IntentServices生存期仅限于onHandleIntent()函数的末尾。通常情况下,它们的寿命不应该超过几秒钟。如果要启动前台,请使用Service类。
此外,正如在最初的答案中说的,一个新的前台API是可用的和首选的Android。
不是问题,只是一个通知:我需要在这里使用地理标志。(如果必要的话,全球定位系统将启动地理定位。
好的完美。看看什么最适合你。
https://stackoverflow.com/questions/46450225
复制相似问题