问题从IntentService迁移到JobOtentService for Android O

时间:2017-10-10 20:17:03

标签: android android-geofence android-service-binding android-8.0-oreo

我正在使用Intent Service来监控Geofence过渡。为此,我正在使用Sticky Service的以下电话。

 LocationServices.GeofencingApi.addGeofences(
                    mGoogleApiClient,
                    getGeofencingRequest(),
                    getGeofencePendingIntent()
            )

并且Pending Intent调用Transition Service(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。

说过我不知道如何返回为JobIntentService创建一个PendingIntent,因为我需要为JobIntentService调用enqueueWork。

任何建议/指针都会受到赞赏。

2 个答案:

答案 0 :(得分:8)

问题

在Android Oreo +设备上从IntentService迁移到JobIntentService时遇到了同样的问题。

我发现的所有指南和摘要都不完整,他们忽略了迁移对使用PendingIntent.getServce所带来的重大变化。

特别是,此迁移会破坏计划启动服务的所有Alarm AlarmManager,并且任何Actions都会添加到启动服务的Notification

解决方案

  

PendingIntent.getService替换为PendingIntent.getBroadcast的{​​{1}}。

     

然后,此接收者使用BroastcastReceiver启动JobIntentService

迁移多个服务时,这可能会重复且容易出错。

为了使这更容易和服务无关,我创建了一个通用enqueueWork,其中包含StartJobIntentServiceReceiver的作业ID和Intent

当接收器启动时,它将启动具有作业ID的原始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包裹在接收机的静态方法{@ 1}}中, Intent

实施例

您可以立即启动接收器,并通过扩展您的JobIntentService

StartJobIntentServiceReceiver.getIntent

如果您没有立即启动服务,则必须使用JobIntentService,例如将Context.sendBroadcast(StartJobIntentServiceReceiver.getIntent(context, intent, job_id)); PendingIntent一起安排或将Alarms添加到{{} 1}} S:

AlarmManager

答案 1 :(得分:1)

正如@andrei_zaitcev建议的那样,我实现了我的自定义BroadCastReceiver并调用了服务的enqueueWork(),这非常有效。