Проблема
У меня возникла такая же проблема при переходе с IntentService
на JobIntentService
на устройствах Android Oreo +.
Все руководства и фрагменты, которые я нашел, неполны, они не учитывают критические изменения, которые эта миграция внесла в использование PendingIntent.getServce
.
В частности, эта миграция прерывает любые Alarm
s, запланированные для запуска службы с AlarmManager
, и любые Actions
, добавленные к Notification
, запускающие службу.
Решение
Замените PendingIntent.getService
на PendingIntent.getBroadcast
, который начинает BroastcastReceiver
.
Затем этот приемник запускает JobIntentService
, используя enqueueWork
.
Это может повторяться и приводить к ошибкам при переносе нескольких служб.
Чтобы сделать это проще и не зависеть от обслуживания, я создал общий StartJobIntentServiceReceiver
, который принимает идентификатор задания и Intent
, предназначенный для JobIntentService
.
Когда получатель запускается, он запускает первоначально заданный JobIntentService
с идентификатором задания и фактически пересылает исходное содержимое Intent
скрытой службе службы.
/**
* 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());
}
}
}
Вам нужно будет заменить имена пакетов своими собственными и зарегистрировать это BroadcastReceiver
как обычно в вашем AndroidManifest.xml
:
<receiver android:name=".path.to.receiver.here.StartJobIntentServiceReceiver"/>
Теперь вы можете безопасно использовать Context.sendBroadcast
или PendingIntent.getBroadcast
где угодно, просто оберните Intent
, который вы хотите доставить на ваш JobIntentService
статический метод приемника, StartJobIntentServiceReceiver.getIntent
.
Примеры
Вы можете запустить приемник, а затем и ваш JobIntentService
, сразу, выполнив следующие действия:
Context.sendBroadcast(StartJobIntentServiceReceiver.getIntent(context, intent, job_id));
Везде, где вы не запускаете службу немедленно, вы должны использовать PendingIntent
, например, при планировании Alarms
с AlarmManager
или добавлении Action
s к Notification
s:
PendingIntent.getBroadcast(context.getApplicationContext(),
request_code,
StartJobIntentServiceReceiver.getIntent(context, intent, job_id),
PendingIntent.FLAG_UPDATE_CURRENT);
person
Cord Rehn
schedule
15.03.2018