【翻译】关于jobIntentService的释义

目前在Android-P开发中,需要在接收到Push广播后,后台启动Service实现Notification的功能。

在Android-O或O之前,可以在WakefulBroadcastReceiver通过startWakefulService(context,intent)正常启动服务。

startWakefulService是通过context.StartService的同时,也通过PowerManager创建一个PARTIAL_WAKE_LOCK类型的唤醒锁(acquire(60*1000)持续时间1分钟后自动释放锁),保证Receiver与Service工作交接过程中设备不会进入休眠状态。然后在IntentService的onHandleIntent中完成提示工作后,通过WakefulBroadcastReceiver.completeWakefulIntent(intent)来释放唤醒锁

 public static ComponentName startWakefulService(Context context, Intent intent) {
        synchronized (sActiveWakeLocks) {
            int id = mNextId;
            mNextId++;
            if (mNextId <= 0) {
                mNextId = 1;
            }

            intent.putExtra(EXTRA_WAKE_LOCK_ID, id);
            ComponentName comp = context.startService(intent);
            if (comp == null) {
                return null;
            }

            PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
            PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                    "wake:" + comp.flattenToShortString());
            wl.setReferenceCounted(false);
            wl.acquire(60 * 1000);
            sActiveWakeLocks.put(id, wl);
            return comp;
        }
    }

但是在Android-P,接收到push信息后想在后台启动Service的话,就会报错并退出app。

java.lang.IllegalStateException:Not allowed to start service Intent :xxx
...
Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=package/xxx.xxxService }: app is in background uid UidRecord

报错的原因是因为在Android-O之后,不再允许后台启动Service。

This class is deprecated.
As of Android O, background check restrictions make this class no longer generally useful. (It is generally not safe to start a service from the receipt of a broadcast, because you don't have any guarantees that your app is in the foreground at this point and thus allowed to do so.) Instead, developers should use android.app.job.JobScheduler to schedule a job, and this does not require that the app hold a wake lock while doing so (the system will take care of holding a wake lock for the job).

所以接收到Push信息后,一旦应用程序在后台运行启动Service就会报错。所以采纳google的建议,使用JobScheduler来进行前台启动Service。通过JobScheduler调度的服务有两种,分别是JobService和JobIntentService。因为原本代码使用的是IntentService,且JobService需要通过开启AsyncTask线程来执行耗时操作而JobIntentService会自动开启子线程来处理操作,所以综上考虑,采用JobIntentService代替IntentService来进行前台启动服务,发送Notification通知。

-----------------------------------------------------------

铺垫这么多,现在来一起了解一下JobIntentService吧

-----------------------------------------------------------

Helper for processing work that has been enqueued for a job/service. When running on Android O or later, the work will be dispatched as a job via JobScheduler.enqueue. When running on older versions of the platform, it will use Context.startService.

You must publish your subclass in your manifest for the system to interact with. This should be published as a JobService, as described for that class, since on O and later platforms it will be executed that way.

Use enqueueWork(Context, Class, int, Intent) to enqueue new work to be dispatched to and handled by your service. It will be executed in onHandleWork(Intent).

You do not need to use WakefulBroadcastReceiver when using this class. When running on Android O, the JobScheduler will take care of wake locks for you (holding a wake lock from the time you enqueue work until the job has been dispatched and while it is running). When running on previous versions of the platform, this wake lock handling is emulated in the class here by directly calling the PowerManager; this means the application must request the Manifest.permission.WAKE_LOCK permission.

根据Google的描述:1.JobIntentService是用来帮助处理已经进入队列的Service/Job

                                 2.在Android-O之前,通过context.startService来启动JobIntentService,

                                    在Android-O&以后,会通过JobScheduler.enqueue来分派工作。(JobIntentService需要在AndroidManifest中定义,与JobService定义一样,需添加权限"android.permission.BIND_JOB_SERVICE")

                                 3.使用JobScheduler分派工作的时候,在处理工作的过程中会保持唤醒锁。不需要使用WakefulBroadcast。不过需要申请WAKE_LOCK权限。

且当中提到JobIntentService在O前后的区别:

1.在O之前,不管设备在休眠或者在其他状态,enqueueWork会立即执行启动Service。但在执行Job的时候,因受到Job的JobInfo.Builder.setOverrideDeadline(long) of 0的JobScheduler政策约束:在设备休眠时,job不会工作,且在设备处于多个任务进行导致的内存占用过大下的状态下会比Service延迟更多执行。

2.Service可以无限期地运行,尽管运行越长时间越容易被系统杀掉,或者因为内存占用过大而被杀掉。而Job在执行时,会受到JobService的执行时间限制,在停止Job的执行后,过段时间会重新调度JobScheduler再次执行Job。Job并不会因为内存占用过大而停止工作,会根据内存状态来调整并发执行的Job数量。

When running as a pre-O service, the act of enqueueing work will generally start the service immediately, regardless of whether the device is dozing or in other conditions. When running as a Job, it will be subject to standard JobScheduler policies for a Job with a JobInfo.Builder.setOverrideDeadline(long) of 0: the job will not run while the device is dozing, it may get delayed more than a service if the device is under strong memory pressure with lots of demand to run jobs.

When running as a pre-O service, the normal service execution semantics apply: the service can run indefinitely, though the longer it runs the more likely the system will be to outright kill its process, and under memory pressure one should expect the process to be killed even of recently started services. When running as a Job, the typical JobService execution time limit will apply, after which the job will be stopped (cleanly, not by killing the process) and rescheduled to continue its execution later. Job are generally not killed when the system is under memory pressure, since the number of concurrent jobs is adjusted based on the memory state of the device.

--------------

下面介绍一下JobIntentService的几个方法:

1.enqueueWork(Context context, ComponentName component, int jobId, Intentwork)

   enqueueWork(Context context, Class class, int jobId, Intentwork):

   调用此函数可以启动JobIntentService的开始工作。

2.onHandleWork(Intent intent):

   为Service处理和分配work。

代码演示:

import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Toast;

import androidx.core.app.JobIntentService;

/**
 * Example implementation of a JobIntentService.
 */
public class SimpleJobIntentService extends JobIntentService {
    /**
     * Unique job ID for this service.
     */
    static final int JOB_ID = 1000;   //JobId->为每个Job分配单独的ID

    /**
     * 启动SimpleJobIntentService,job会在onHandleWork执行
     */
    static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, SimpleJobIntentService.class, JOB_ID, work);
    }

    @Override
    protected void onHandleWork(Intent intent) {
        // We have received work to do.  The system or framework is already
        // holding a wake lock for us at this point, so we can just go.
        Log.i("SimpleJobIntentService", "Executing work: " + intent);
        String label = intent.getStringExtra("label");
        if (label == null) {
            label = intent.toString();
        }
        toast("Executing: " + label);
        for (int i = 0; i < 5; i++) {
            Log.i("SimpleJobIntentService", "Running service " + (i + 1)
                    + "/5 @ " + SystemClock.elapsedRealtime());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        }
        Log.i("SimpleJobIntentService", "Completed service @ " + SystemClock.elapsedRealtime());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        toast("All work complete");
    }

    final Handler mHandler = new Handler();

    // Helper for showing tests
    void toast(final CharSequence text) {
        mHandler.post(new Runnable() {
            @Override public void run() {
                Toast.makeText(SimpleJobIntentService.this, text, Toast.LENGTH_SHORT).show();
            }
        });
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值