JobIntentService详解及使用
来源:互联网 发布:网络股票龙头股票 编辑:程序博客网 时间:2024/06/05 18:45
Android o新特性–后台限制
Android8.0对系统资源的管控更加严格,添加了后台限制规则。
如果满足以下任意条件,应用
将被视为处于前台:
- 具有可见 Activity(不管该 Activity 已启动还是已暂停)。
- 具有前台服务。
- 另一个前台应用已关联到该应用(不管是通过绑定到其中一个服务,还是通过使用其中一个内容提供程序)。 例如,如果另一个应用绑定到该应用的服务,那么该应用处于前台:
- IME
- 壁纸服务
- 通知侦听器
- 语音或文本服务
如果以上条件均不满足,应用将被视为处于后台。
系统不允许后台应用创建后台服务。 因此,Android 8.0 引入了一种全新的方法,即 Context.startForegroundService(),以在前台启动新服务。
在系统创建服务后应用有五秒的时间来调用该服务的 startForeground() 方法以显示新服务的用户可见通知。
如果应用在此时间限制内未调用 startForeground(),则系统将停止服务并声明此应用为 ANR
。
Android强制开发者使用 JobScheduler 作业替换后台服务的意思,使用jobIntentService就可以比较方便的使用JobScheduler这个工具。
特殊情况是可以创建后台服务的:
- 处理对用户可见的任务时,应用将被置于白名单中,后台应用将被置于一个临时白名单中并持续数分钟。 位于白名单中时,应用可以无限制地启动服务,并且其后台服务也可以运行。
- 处理一条高优先级 Firebase 云消息传递 (FCM) 消息。
- 接收广播,例如短信/彩信消息。
- 从通知执行 PendingIntent。
- bindService不受后台限制
JobIntentService
JobIntentService实质为Service其继承关系如下所示。
java.lang.Object ↳ android.content.Context ↳ android.content.ContextWrapper ↳ android.app.Service ↳ android.support.v4.app.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.
官方文档解释为,用于处理被加入到job或service任务的一个辅助工具,8.0以下被当作普通的Intent使用startSerivce()启动service来执行。
8.0以上任务被作为job用jobScheduler.enqueue()方法来分发,
说到Jobscheduler,应该不陌生了,框架提供的用来APP调度任务的接口,根据APP要求构建JobInfo,系统会在适当的时间调用JobInfo指定的JobService来执行你的任务。
所以在Android8.0及以上JobIntentService和JobService做的事情是相同的,都是等着JobScheduler分配任务来执行。
不同点在于,JobService使用的handler使用的是主线程的Looper,因此需要在onStartJob()中手动创建AsyncTask去执行耗时任务,而JobIntentService则帮我们处理这一过程,使用它只需要写需要做的任务逻辑即可,不用关心卡住主线程的问题。另外,向jobScheduler传递任务操作也更简单了,不需要在指定JobInfo中的参数,直接enqueue(context,intent)就可以。
这有点像Service和IntentService的关系。
来看一段JobIntentService的源码
加入enqueue到onhandlework的过程。
//JobIntentService的入口方法public static void enqueueWork(@NonNull Context context, @NonNull Class cls, int jobId, @NonNull Intent work) { if (work == null) { throw new IllegalArgumentException("work must not be null"); } synchronized (sLock) { WorkEnqueuer we = getWorkEnqueuer(context, cls, true, jobId);//根据版本获取不同的WorkEnqueuer we.ensureJobId(jobId);//每个jobIntentService 唯一对应一个JobId,所有给这个service的work都必须相同 we.enqueueWork(work);//调用WorkEnqueuer } }
static WorkEnqueuer getWorkEnqueuer(Context context, Class cls, boolean hasJobId, int jobId) { WorkEnqueuer we = sClassWorkEnqueuer.get(cls); if (we == null) { if (BuildCompat.isAtLeastO()) { if (!hasJobId) { throw new IllegalArgumentException("Can't be here without a job id"); } we = new JobWorkEnqueuer(context, cls, jobId);//8.0 } else { we = new CompatWorkEnqueuer(context, cls);//8.0以前 } sClassWorkEnqueuer.put(cls, we); } return we; } //8.0的WorkEnqueuer.enqueueWork() @Override void enqueueWork(Intent work) { if (DEBUG) Log.d(TAG, "Enqueueing work: " + work); mJobScheduler.enqueue(mJobInfo, new JobWorkItem(work));//调用JobScheduler.enqueue() }
看到最终调用了JobScheduler来调度任务,那么是给哪个service执行呢,看mJobInfo怎么build的
JobWorkEnqueuer(Context context, Class cls, int jobId) { super(context, cls); ensureJobId(jobId); JobInfo.Builder b = new JobInfo.Builder(jobId, mComponentName);//使用mComponentName mJobInfo = b.setOverrideDeadline(0).build(); mJobScheduler = (JobScheduler) context.getApplicationContext().getSystemService( Context.JOB_SCHEDULER_SERVICE); }
使用mComponentName,那这个mComponentName在哪赋值
//JobWorkEnqueuer的父类 WorkEnqueuer(Context context, Class cls) { mComponentName = new ComponentName(context, cls);
所以mComponentName就是在enqueueWork(@NonNull Context context, @NonNull Class cls, int jobId,@NonNull Intent work)中传入的service的类名,一般在调用JobIntentService时就会传入其子类的类名。
那么work在哪被处理的呢,按照jobService的逻辑找到onStartJob(),就是执行任务处理的地方
public boolean onStartJob(JobParameters params) { if (DEBUG) Log.d(TAG, "onStartJob: " + params); mParams = params; // We can now start dequeuing work! mService.ensureProcessorRunningLocked(); return true; } void ensureProcessorRunningLocked() { if (mCurProcessor == null) { mCurProcessor = new CommandProcessor(); if (DEBUG) Log.d(TAG, "Starting processor: " + mCurProcessor); mCurProcessor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);//mCurProcessor是线程池的AsyncTask } } final class CommandProcessor extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { GenericWorkItem work; if (DEBUG) Log.d(TAG, "Starting to dequeue work..."); while ((work = dequeueWork()) != null) { if (DEBUG) Log.d(TAG, "Processing next work: " + work); onHandleWork(work.getIntent()); //回调onHandleWork() if (DEBUG) Log.d(TAG, "Completing work: " + work); work.complete(); } if (DEBUG) Log.d(TAG, "Done processing work!"); return null; }
子类实现jobIntentService处理work就是实现onHandleWork,可以看到其使用线程池的AsyncTask来处理work的,所以不需要考虑主线程阻塞的问题。
案例演示
public class MainActivity extends Activity { Button btn ; static int num =0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn = findViewById(R.id.button); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent workIntent = new Intent(); num++; Log.d("houson", "onClick: "+num); workIntent.putExtra("work","work num:"+num); MyJobIntentService.enqueueWork(getApplicationContext(),workIntent); } }); }}
public class MyJobIntentService extends JobIntentService { /** * 这个Service 唯一的id */ static final int JOB_ID = 10111; /** * Convenience method for enqueuing work in to this service. */ static void enqueueWork(Context context, Intent work) { enqueueWork(context, MyJobIntentService.class, JOB_ID, work); } @Override protected void onHandleWork( Intent intent) { Log.d("houson", "onHandleWork: "+intent.getStringExtra("work").toString()); }}
注意manifest!
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission><service android:name=".MyJobIntentService"></service>
结果:
11-06 20:39:04.116 20653-20653/com.example.houson.jobintentservicedemo D/houson: onClick: 4711-06 20:39:04.135 20653-20743/com.example.houson.jobintentservicedemo D/houson: onHandleWork: work num:4711-06 20:39:04.216 20653-20653/com.example.houson.jobintentservicedemo D/houson: onClick: 4811-06 20:39:04.234 20653-20745/com.example.houson.jobintentservicedemo D/houson: onHandleWork: work num:48
总结
由于Android O的后台限制,创建后台服务需要使用JobScheduler来由系统进行调度任务的执行,而使用JobService的方式比较繁琐,8.0及以上提供了JobIntentService帮助开发者更方便的将任务交给JobScheduler调度,其本质是Service后台任务在他的OnhandleWork()中进行,子类重写该方法即可。使用较简单。
注意
:
1.需要添加android.permission.WAKE_LOCK权限,JobIntentService处理了亮屏/锁屏,因此要此权限。
2.注册JobintentService也是service
- JobIntentService详解及使用
- Cursor 详解及使用
- lsof详解及使用
- BulletedList使用及详解
- BulletedList使用及详解
- Pinyin4j 详解及使用
- Spring详解及使用
- JDOM使用详解及实例
- JDOM使用详解及实例
- jdom使用详解及实例
- JDOM使用详解及实例
- JDOM使用详解及实例
- JDOM使用详解及实例
- JDOM使用详解及实例
- JDOM使用详解及实例
- JDOM使用详解及实例
- SimpleDateFormat 使用详解及实例
- PayPal注册及使用详解
- 对话框Dialog的应用
- foreachActive方法
- Android 利用Gradle实现app的环境分离
- exec,exit,wait,waitpid,sleep函数复习
- 算法笔记 //10_删数问题
- JobIntentService详解及使用
- Unity3D手机斗地主游戏开发实战(03)_地主牌显示和出牌逻辑(不定期更新中~~~)
- 51nod 1285 山峰和分段
- HashTable
- 构建布局良好的windows环境
- View的绘制流程
- 单链表的基本操作(头结点)
- Qt中Debug设置断点无效
- Python numpy 中的sum使用方法