I'm trying to construct a geofencing app, but it seems to only register geofences when the main activity started, and the intent service stops receiving them when the app is closed. So, I moved the add geofence logic into the intent service (along with the intent handling code) and make sure that service gets started, but now the service doesn't get receive any intents at all!
Service definition
public class GeofenceTransitionsIntentService extends IntentService implements ConnectionCallbacks, OnConnectionFailedListener, ResultCallback<Status>
Everything in the service (google api client built and connected) is done in onCreate
, with both the intent handlers and the geofence registration stuff onConnected
registers geofences, etc. Basically, I've tried to implement heavily borrowed geofencing sample code (from the docs) in the same service intended to handle those intents.
All the main activity does is starts the service and draws things related to the geofence notifications received in the service.
If you need more info, just let me know.
edit
Ok so it seems like we need more information -- an outline of the service:
public class GeofenceTransitionsIntentService extends IntentService implements ConnectionCallbacks, OnConnectionFailedListener, ResultCallback<Status> {
protected static final String TAG = "GeofenceTransitionsIS";
protected GoogleApiClient mGoogleApiClient;
protected ArrayList<Geofence> mGeofenceList;
private boolean mGeofencesAdded;
private PendingIntent mGeofencePendingIntent;
private SharedPreferences mSharedPreferences;
public GeofenceTransitionsIntentService() {
super(TAG);
}
@Override
public void onCreate() {
super.onCreate();
buildGoogleApiClient();
populateGeofenceList();
mGoogleApiClient.connect();
}
...
@Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
// handle the intent, send a notification
}
private void sendNotification(String notificationDetails) {
// sends a notification
}
@Override
public void onConnected(Bundle connectionHint)
{
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this);
}
// straight out of the example
private GeofencingRequest getGeofencingRequest()
{
...
}
// from a branch of the example that reuses the pending intent
private PendingIntent getGeofencePendingIntent()
{
if (mGeofencePendingIntent != null)
{
return mGeofencePendingIntent;
}
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
mGeofencePendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return mGeofencePendingIntent;
}
public void populateGeofenceList() {
for (thing place : listofplaces) {
mGeofenceList.add(...)
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
public void onResult(Status status)
{
// were fences added? usually yes
}
}
My research has been frustrating -- I see people claiming to be able to do something like this from a broadcast receiver (see first comment) but not from a service?
I have a pretty mangled manifest.xml from all the revisions I've been working through:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<application
android:allowBackup="true"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service android:name=".GeofenceTransitionsIntentService"
android:exported="true"
android:enabled="true">
<intent-filter >
<action android:name="com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE"/>
</intent-filter>
</service>
...
</application>
Neither adding the intent-filter
nor the android:exported="true"
to the service definition helped at all.
First, don't use the IntentService for this. Its sole purpose is to get a single intent, run it in a background thread, then stops itself. What you are looking for is a Service, as this will stick around for a while (until the OS starts running low on resources).
Second, once you move your code to a Service, do the following:
Keep in mind that Android will kill your service when it runs low on resources, without much if any warning. I strongly suggest you look into starting in the foreground if you need this service to run at a higher priority.
Third, now that we have the service setup, you may have noticed the
getGeofencePendingIntent()
function now uses a BroadcastReceiver instead of the service it is running in. Here is how you set that up:Fourth, you'll need to modify your Manifest to let the app know that this BroadcastReceiver should be used:
I'm not sure why you are using the export and enabled flags, but they don't need to be declared, because enabled is set by default, and exported is defaulted "true" if you have an intent-filter.
I would suggest you read up on Activity, Service, and BroadcastReceiver life cycles, as understanding that would greatly benefit you with this project and give you a better understanding of the pain of Android in general.