问题从IntentService迁移到Android O的JobIntentService

Aks*_*hay 3 android android-geofence android-service-binding android-8.0-oreo

我正在使用Intent Service来监控Geofence过渡.为此,我正在使用Sticky Service的跟随电话.

 LocationServices.GeofencingApi.addGeofences(
                    mGoogleApiClient,
                    getGeofencingRequest(),
                    getGeofencePendingIntent()
            )
Run Code Online (Sandbox Code Playgroud)

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);
    }
Run Code Online (Sandbox Code Playgroud)

这工作很好Pre Oreo.但是,我必须将我的粘性服务转换为JobScheduler,我需要将GeofenceTransitionsIntentService哪个是intentService 转换为JobIntentService.

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

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

Cor*_*ehn 9

问题

从Android Oreo +设备迁移IntentServiceJobIntentServiceAndroid 时,我遇到了同样的问题.

我发现的所有指南和片段都不完整,它们忽略了迁移对使用的重大变化PendingIntent.getServce.

特别是,此迁移会破坏Alarm计划启动服务的任何计划,AlarmManagerActions添加任何Notification已启动服务的服务.


替换PendingIntent.getServicePendingIntent.getBroadcast开始a BroastcastReceiver.

然后该接收器开始JobIntentService使用enqueueWork.


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

为了使这更容易和服务无关,我创建了一个通用的StartJobIntentServiceReceiver,它带有一个工作ID和一个Intent意图JobIntentService.

当接收器启动时,它将JobIntentService以作业ID 启动最初的预期,并实际将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());
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

您需要用自己的名称替换包名称,并BroadcastReceiver在以下情况下按常规注册AndroidManifest.xml:

<receiver android:name=".path.to.receiver.here.StartJobIntentServiceReceiver"/>
Run Code Online (Sandbox Code Playgroud)

您现在可以安全使用Context.sendBroadcastPendingIntent.getBroadcast在任何地方使用,只需将Intent您希望交付的内容包装JobIntentService在接收器的静态方法中,StartJobIntentServiceReceiver.getIntent.


例子

您可以通过以下方式JobIntentService立即启动接收器,并通过扩展您:

Context.sendBroadcast(StartJobIntentServiceReceiver.getIntent(context, intent, job_id));
Run Code Online (Sandbox Code Playgroud)

如果您没有立即启动服务,则必须使用a PendingIntent,例如在Alarms使用s AlarmManager或向Actions 添加s时Notification:

PendingIntent.getBroadcast(context.getApplicationContext(),
    request_code,
    StartJobIntentServiceReceiver.getIntent(context, intent, job_id),
    PendingIntent.FLAG_UPDATE_CURRENT);
Run Code Online (Sandbox Code Playgroud)


Aks*_*hay -1

正如 @andrei_zaitcev 所建议的,我实现了自定义的 BroadCastReceiver 和enqueueWork()服务调用,效果非常好。

  • 您能提供一个实施示例吗?当我将应用程序升级到奥利奥时,一直在寻找类似的解决方案。 (3认同)