Android O 从 IntentService 转移到 JobIntentService 的问题
Issue Moving from IntentService to JobIntentService for Android O
我正在使用 Intent Service 来监控地理围栏转换。为此,我正在使用粘性服务的以下呼叫。
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
)
并且 Pending Intent 调用 Transition 服务(一个 IntentService),如下所示。
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);
}
Pre Oreo 效果很好。但是,我必须将我的粘性服务转换为 JobScheduler,我需要将 GeofenceTransitionsIntentService
这是一个 intentService 转换为 JobIntentService。
话虽如此,我不确定如何return为 JobIntentService 创建一个 PendingIntent,因为我需要为 JobIntentService 调用 enqueueWork。
任何 suggestions/pointer 将不胜感激。
按照@andrei_zaitcev的建议,我实现了我的自定义 BroadCastReceiver 并调用了服务的 enqueueWork()
,效果很好。
问题
我在 Android Oreo+ 设备上从 IntentService
迁移到 JobIntentService
时遇到了同样的问题。
我发现的所有指南和片段都不完整,它们遗漏了此迁移对 PendingIntent.getServce
.
使用的重大更改
特别是,此迁移中断了计划启动服务的任何 Alarm
和 AlarmManager
以及添加到启动服务的 Notification
的任何 Actions
。
解决方案
Replace PendingIntent.getService
with PendingIntent.getBroadcast
that starts a BroastcastReceiver
.
This receiver then starts the JobIntentService
using enqueueWork
.
迁移多个服务时,这可能会重复且容易出错。
为了使这更容易和服务不可知,我创建了一个通用的 StartJobIntentServiceReceiver
,它接受一个工作 ID 和一个 Intent
表示 JobIntentService
。
当接收器启动时,它会使用作业 ID 启动最初打算的 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());
}
}
}
您需要用您自己的包名称替换包名称,并像往常一样在您的 AndroidManifest.xml
:
中注册这个 BroadcastReceiver
<receiver android:name=".path.to.receiver.here.StartJobIntentServiceReceiver"/>
您现在可以安全地在任何地方使用 Context.sendBroadcast
或 PendingIntent.getBroadcast
,只需将要发送到 JobIntentService
的 Intent
包装在接收方的静态方法中,StartJobIntentServiceReceiver.getIntent
.
例子
您可以立即启动接收器,并扩展您的 JobIntentService
:
Context.sendBroadcast(StartJobIntentServiceReceiver.getIntent(context, intent, job_id));
如果您不立即启动服务,则必须使用 PendingIntent
,例如在使用 AlarmManager
安排 Alarms
或向 [= 添加 Action
时20=]s:
PendingIntent.getBroadcast(context.getApplicationContext(),
request_code,
StartJobIntentServiceReceiver.getIntent(context, intent, job_id),
PendingIntent.FLAG_UPDATE_CURRENT);
我正在使用 Intent Service 来监控地理围栏转换。为此,我正在使用粘性服务的以下呼叫。
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
)
并且 Pending Intent 调用 Transition 服务(一个 IntentService),如下所示。
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);
}
Pre Oreo 效果很好。但是,我必须将我的粘性服务转换为 JobScheduler,我需要将 GeofenceTransitionsIntentService
这是一个 intentService 转换为 JobIntentService。
话虽如此,我不确定如何return为 JobIntentService 创建一个 PendingIntent,因为我需要为 JobIntentService 调用 enqueueWork。
任何 suggestions/pointer 将不胜感激。
按照@andrei_zaitcev的建议,我实现了我的自定义 BroadCastReceiver 并调用了服务的 enqueueWork()
,效果很好。
问题
我在 Android Oreo+ 设备上从 IntentService
迁移到 JobIntentService
时遇到了同样的问题。
我发现的所有指南和片段都不完整,它们遗漏了此迁移对 PendingIntent.getServce
.
特别是,此迁移中断了计划启动服务的任何 Alarm
和 AlarmManager
以及添加到启动服务的 Notification
的任何 Actions
。
解决方案
Replace
PendingIntent.getService
withPendingIntent.getBroadcast
that starts aBroastcastReceiver
.This receiver then starts the
JobIntentService
usingenqueueWork
.
迁移多个服务时,这可能会重复且容易出错。
为了使这更容易和服务不可知,我创建了一个通用的 StartJobIntentServiceReceiver
,它接受一个工作 ID 和一个 Intent
表示 JobIntentService
。
当接收器启动时,它会使用作业 ID 启动最初打算的 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());
}
}
}
您需要用您自己的包名称替换包名称,并像往常一样在您的 AndroidManifest.xml
:
BroadcastReceiver
<receiver android:name=".path.to.receiver.here.StartJobIntentServiceReceiver"/>
您现在可以安全地在任何地方使用 Context.sendBroadcast
或 PendingIntent.getBroadcast
,只需将要发送到 JobIntentService
的 Intent
包装在接收方的静态方法中,StartJobIntentServiceReceiver.getIntent
.
例子
您可以立即启动接收器,并扩展您的 JobIntentService
:
Context.sendBroadcast(StartJobIntentServiceReceiver.getIntent(context, intent, job_id));
如果您不立即启动服务,则必须使用 PendingIntent
,例如在使用 AlarmManager
安排 Alarms
或向 [= 添加 Action
时20=]s:
PendingIntent.getBroadcast(context.getApplicationContext(),
request_code,
StartJobIntentServiceReceiver.getIntent(context, intent, job_id),
PendingIntent.FLAG_UPDATE_CURRENT);