Geofence events not always called

*爱你&永不变心* 提交于 2019-12-04 17:17:53

For starters, I would not put this code inside a BroadcastReceiver.

Besides being bad practice, the component might be shutdown before the code has finished executing.

Please consider starting a Service from your Receiver, if you need to run code that might take some time. Otherwise for a short execution time, you may use an IntentService.

By looking at your code, I'm aware of two reasons your Geofences are not working as expected:

1) The nature of Geofences

Geofences API retrieves your location mostly from WiFi / Cellular Data, which is often unavailable.

I tried to use Geofences once, and I found them very inaccurate. I switched to LocationManager making it use pure GPS location and it met my expectations.

Please see this answer, which advises to

Poll the GPS hardware on an interval without doing anything with the result and you'll start getting more accurate geofences.

I have never tried Google's FusedLocation API, but I have heard people saying it worked very well for them.

If you use LocationManager, you will have to implement your 'Geofencing logic' yourself; you can easily do it with Location.distanceTo(Location).

Example:

final float distanceFromCenter = currentLocation.distanceTo(this.destination);

if (distanceFromCenter <= YOUR_RADIUS_IN_METERS) {
   // you are inside your geofence
} 

2) CPU is not active

The fact that the Geofences are active, does not necessarily mean that your phone is awake and computing location checks.

To fix that, you can start a ForegroundService from your BroacastReceiver. The Service should hold a partial WakeLock as well. This guarantees that:

  1. The OS does not kill the service (or better: less chance to be killed...)
  2. The user is aware of the service and can dismiss it if necessary
  3. The CPU is running. Therefore you can be sure that the code that retrieves the location is running (please remember to to release the WakeLock when the service stops).

Please note that Android may still kill your service if necessary.

You can find plenty of examples on the web on how to start a ForegroundService from a BroadcastReceiver, how to hold a WakeLock and so on...

Also, check out to the new Android O API, that brought some minor changes to the ForegroundService and other components.

PS: I have developed and application that uses all the components mentioned above (except for the FusedLocation) and I was extremely satisfied.

EDIT: Answering OP's questions

Okey, let's try to make some order here, otherwise future readers may easily get confused. I'll start by answering what written in the original question and the 'bounty banner', then the OP edits, and finally the questions the OP placed in the comments.

1) Original question

Is the triggering event also being dismissed, when the app is cleaned by the garbage collector?

Most probably yes. See this answer where OP implemented a service that runs in a separate process, in order to make geofence be triggered even when the app is killed.

I need to understand what causes the geofences not to get called, if enough time has passed

Plenty of reasons. See my original answer.

I saw an implementation of the geofence logic with an Service instead of a broadcast receiver, will that work better?

A Receiver and a Service are two different things. Please read Android's documentation. You can start a Service from a BroadcastReceiver, which is usually the preferred way to 'receive' PendingIntents and do something with them.

2) Edits

  • Please note that I did not tell you to replace the BroadcastReceiver with a Service, but that it might be a good idea to start a Service from your Receiver and handle all your logic there.
  • Making your IntentService a Singleton class is not necessary as (from IntentService documentation)

All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.

  • Do not store Context into a Singleton class or some static references. I'm impressed Android Studio did not warn you.

3) Comments

I need this to work 24/7 hence I cannot use the location all the time, cause of obvious battery issues.

Please read Android Oreo Background Execution Limits. This might be an issue for you.

Also now that I changed to a intentService, is that enough to ensure it should stay awake?

No, as I said, you probably need a partial WakeLock in order to turn on the CPU.

Do I need to initiate it another way, in order to keep it in the foreground?

Yes. In order to start a Foreground Service, you need to call startForeground(int, Notification)

Please note: IntentServices lifespan is limited to the end of the onHandleIntent() function. They are not supposed to live for more than a few seconds, typically. Use the Service class if you want to start a Foreground.

Moreover, as said in the original answer, a new Foreground API is available and preferred for Android Oreo.

Not a question, just a notice: I need to use here Geofencing. (Geofencing will start if necessary the gps

Ok perfect. See what works best for you.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!