Android O从IntentService迁移到JobIntentService的问题

Android O从IntentService迁移到JobIntentService的问题,android,android-geofence,android-service-binding,android-8.0-oreo,Android,Android Geofence,Android Service Binding,Android 8.0 Oreo,我正在使用Intent服务来监视Geofence转换。为此,我使用了粘性服务的以下调用 LocationServices.GeofencingApi.addGeofences( mGoogleApiClient, getGeofencingRequest(), getGeofencePendingIntent() ) 挂起的Intent调用转换服务(

我正在使用Intent服务来监视Geofence转换。为此,我使用了粘性服务的以下调用

 LocationServices.GeofencingApi.addGeofences(
                    mGoogleApiClient,
                    getGeofencingRequest(),
                    getGeofencePendingIntent()
            )
挂起的Intent调用转换服务(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);
    }
这在奥利奥之前效果很好。但是,我必须将sticky服务转换为JobScheduler,并且需要将intentService转换为JobIntentService的GeofenceTransitionsIntentService

话虽如此,我不确定如何返回并为JobIntentService创建PendingEvent,因为我需要为JobIntentService调用enqueueWork


任何建议/指针都将不胜感激。

正如@andrei_zaitcev所建议的那样,我实现了我的自定义广播接收器,并调用了服务的
enqueueWork()
,效果非常好。

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

我发现的所有指南和代码片段都不完整,它们遗漏了这次迁移对
pendingent.getServce
使用的突破性改变

特别是,此迁移会中断计划使用
AlarmManager
启动服务的任何
报警
,以及添加到启动服务的
通知中的任何
操作


解决方案 将
pendingent.getService
替换为启动
broastcastereceiver
pendingent.getBroadcast

然后,此接收器使用
排队工作
启动
JobIntentService


迁移多个服务时,这可能是重复的,并且容易出错

为了使这变得更简单和服务不可知,我创建了一个通用的
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"/>
在不立即启动服务的任何地方,必须使用
挂起内容
,例如使用
AlarmManager
调度
报警
或将
操作
s添加到
通知
s:

PendingIntent.getBroadcast(context.getApplicationContext(),
    request_code,
    StartJobIntentServiceReceiver.getIntent(context, intent, job_id),
    PendingIntent.FLAG_UPDATE_CURRENT);

我知道,张贴网址是不推荐的,因为网站可能会消失。但这里有一个网站的例子,我一直在说,如果有人好奇的话,创建地理围栏。将BroadcastReceiver用作Geofence API的挂起意图。然后在Geofence API触发后,在此BroadcastReceive中安排一个作业。我想,Android O不建议使用广播receiver@andrei_zaitcev在这种情况下,您会为广播推荐什么意图过滤器?尤其是记住Android Oreo?Android Oreo对广播接收机没有任何背景限制。您可以保留它,而无需任何目的过滤器。如果你的应用程序处于所谓的后台模式,你就不能从这个接收器运行后台服务。你会有一个实现的例子吗?当我将一个应用升级到Oreo时,我一直在寻找一个类似的解决方案。你可以在他们的geofence示例中看到这种方法,但我无法让它起作用,令人惊讶的是,它被弃用了!为O更新的代码怎么会被弃用??Jesus Google因为这堆愚蠢的废话得了F。就你的观点而言,
在迁移多个服务时,这可能是重复的并且容易出错。
这是主观的。您提供的解决方案可能有效,但不是最好的imho,或者至少在我查看google docs时收到回复时,是为了让工作排队。
PendingIntent.getBroadcast(context.getApplicationContext(),
    request_code,
    StartJobIntentServiceReceiver.getIntent(context, intent, job_id),
    PendingIntent.FLAG_UPDATE_CURRENT);