I am using Intent Service to monitor Geofence transition. For that I am using following call from a Sticky Service.
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
)
and the Pending Intent calls Transition service (an IntentService) like below.
private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
// We use FLAG_UPDATE_CURRENT so that we get the
//same pending intent back when calling addgeoFences()
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
This worked fine Pre Oreo. However, I had to convert my sticky service to a JobScheduler and I need to convert GeofenceTransitionsIntentService
which is an intentService to JobIntentService.
Having said that I am not sure how to return create a PendingIntent for JobIntentService, because I need to call enqueueWork for JobIntentService.
Any suggestions/pointer would be appreciated.
This class was deprecated in API level 30. IntentService is subject to all the background execution limits imposed with Android 8.0 (API level 26). Consider using WorkManager or JobIntentService , which uses jobs instead of services when running on Android 8.0 or higher.
Both work same but the only difference with JobIntentService is that JobIntentService gets restarted if the application gets killed while the service was executing.
Provided since Android API 3, the purpose of IntentService was to allow asynchronous tasks to be performed without blocking the main thread. The deprecation is one of a number of steps introduced starting with Android 8.0 (API 26) to limit the actions that can be performed while an app is in the background.
If the Background task is to be performed for a long time we can use the intent service. Service will always run on the main thread. intent service always runs on the worker thread triggered from the main thread.
I had the same issue when migrating from IntentService
to JobIntentService
on Android Oreo+ devices.
All the guides and snippets I've found are incomplete, they leave out the breaking change this migration has on the use of PendingIntent.getServce
.
In particular, this migration breaks any Alarm
s scheduled to start a service with the AlarmManager
and any Actions
added to a Notification
that start a service.
Replace
PendingIntent.getService
withPendingIntent.getBroadcast
that starts aBroastcastReceiver
.This receiver then starts the
JobIntentService
usingenqueueWork
.
This can be repetitive and error prone when migrating multiple services.
To make this easier and service agnostic, I created a generic StartJobIntentServiceReceiver
that takes a job ID and an Intent
meant for a JobIntentService
.
When the receiver is started, it will start the originally intended JobIntentService
with a job ID and actually forwards the Intent
's original contents through to the service behind the scenes.
/**
* A receiver that acts as a pass-through for enqueueing work to a {@link android.support.v4.app.JobIntentService}.
*/
public class StartJobIntentServiceReceiver extends BroadcastReceiver {
public static final String EXTRA_SERVICE_CLASS = "com.sg57.tesladashboard.extra_service_class";
public static final String EXTRA_JOB_ID = "com.sg57.tesladashboard.extra_job_id";
/**
* @param intent an Intent meant for a {@link android.support.v4.app.JobIntentService}
* @return a new Intent intended for use by this receiver based off the passed intent
*/
public static Intent getIntent(Context context, Intent intent, int job_id) {
ComponentName component = intent.getComponent();
if (component == null)
throw new RuntimeException("Missing intent component");
Intent new_intent = new Intent(intent)
.putExtra(EXTRA_SERVICE_CLASS, component.getClassName())
.putExtra(EXTRA_JOB_ID, job_id);
new_intent.setClass(context, StartJobIntentServiceReceiver.class);
return new_intent;
}
@Override
public void onReceive(Context context, Intent intent) {
try {
if (intent.getExtras() == null)
throw new Exception("No extras found");
// change intent's class to its intended service's class
String service_class_name = intent.getStringExtra(EXTRA_SERVICE_CLASS);
if (service_class_name == null)
throw new Exception("No service class found in extras");
Class service_class = Class.forName(service_class_name);
if (!JobIntentService.class.isAssignableFrom(service_class))
throw new Exception("Service class found is not a JobIntentService: " + service_class.getName());
intent.setClass(context, service_class);
// get job id
if (!intent.getExtras().containsKey(EXTRA_JOB_ID))
throw new Exception("No job ID found in extras");
int job_id = intent.getIntExtra(EXTRA_JOB_ID, 0);
// start the service
JobIntentService.enqueueWork(context, service_class, job_id, intent);
} catch (Exception e) {
System.err.println("Error starting service from receiver: " + e.getMessage());
}
}
}
You will need to replace package names with your own, and register this BroadcastReceiver
per usual in your AndroidManifest.xml
:
<receiver android:name=".path.to.receiver.here.StartJobIntentServiceReceiver"/>
You are now safe to use Context.sendBroadcast
or PendingIntent.getBroadcast
anywhere, simply wrap the Intent
you want delivered to your JobIntentService
in the receiver's static method, StartJobIntentServiceReceiver.getIntent
.
You can start the receiver, and by extension your JobIntentService
, immediately by doing this:
Context.sendBroadcast(StartJobIntentServiceReceiver.getIntent(context, intent, job_id));
Anywhere you aren't starting the service immediately you must use a PendingIntent
, such as when scheduling Alarms
with AlarmManager
or adding Action
s to Notification
s:
PendingIntent.getBroadcast(context.getApplicationContext(),
request_code,
StartJobIntentServiceReceiver.getIntent(context, intent, job_id),
PendingIntent.FLAG_UPDATE_CURRENT);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With