一 定义
IntentService 是 Android 里面的一个封装类, 继承自四大组件之一的 Service
二作用
处理异步请求, 实现多线程
三 工作流程
注意: 若启动 IntentService 多次, 那么每个耗时操作则以队列的方式在 IntentService 的 onHandleIntent 回调方法中依次执行, 执行完自动结束
四实现步骤
步骤 1: 定义 IntentService 的子类: 传入线程名称复写 onHandleIntent()方法
步骤 2: 在 Manifest.xml 中注册服务
步骤 3: 在 Activity 中开启 Service 服务
五具体实例
步骤 1: 定义 IntentService 的子类: 传入线程名称复写 onHandleIntent()方法
- package com.example.carson_ho.demoforintentservice;
- import android.app.IntentService;
- import android.content.Intent;
- import android.util.Log;
- /**
- * Created by Carson_Ho on 16/9/28.
- */
- public class myIntentService extends IntentService {
- /* 构造函数 */
- public myIntentService() {
- // 调用父类的构造函数
- // 构造函数参数 = 工作线程的名字
- super("myIntentService");
- }
- /* 复写 onHandleIntent()方法 */
- // 实现耗时任务的操作
- @Override
- protected void onHandleIntent(Intent intent) {
- // 根据 Intent 的不同进行不同的事务处理
- String taskName = intent.getExtras().getString("taskName");
- switch (taskName) {
- case "task1":
- Log.i("myIntentService", "do task1");
- break;
- case "task2":
- Log.i("myIntentService", "do task2");
- break;
- default:
- break;
- }
- }
- @Override
- public void onCreate() {
- Log.i("myIntentService", "onCreate");
- super.onCreate();
- }
- /* 复写 onStartCommand()方法 */
- // 默认实现将请求的 Intent 添加到工作队列里
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- Log.i("myIntentService", "onStartCommand");
- return super.onStartCommand(intent, flags, startId);
- }
- @Override
- public void onDestroy() {
- Log.i("myIntentService", "onDestroy");
- super.onDestroy();
- }
- }
步骤 2: 在 Manifest.xml 中注册服务
- <service android:name=".myIntentService">
- <intent-filter>
- <action android:name="cn.scu.finch" />
- </intent-filter>
- </service>
步骤 3: 在 Activity 中开启 Service 服务
- package com.example.carson_ho.demoforintentservice;
- import android.content.Intent;
- import android.os.Bundle;
- import android.support.v7.app.AppCompatActivity;
- public class MainActivity extends AppCompatActivity {@Override protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- // 同一服务只会开启一个工作线程
- // 在 onHandleIntent 函数里依次处理 intent 请求
- Intent i = new Intent("cn.scu.finch");
- Bundle bundle = new Bundle();
- bundle.putString("taskName", "task1");
- i.putExtras(bundle);
- startService(i);
- Intent i2 = new Intent("cn.scu.finch");
- Bundle bundle2 = new Bundle();
- bundle2.putString("taskName", "task2");
- i2.putExtras(bundle2);
- startService(i2);
- startService(i); // 多次启动
- }
- }
结果
六源码分析
接下来, 我们会通过源码分析解决以下问题:
IntentService 如何单独开启一个新的工作线程;
IntentService 如何通过 onStartCommand()传递给服务 intent 被依次插入到工作队列中
问题 1:IntentService 如何单独开启一个新的工作线程
- // IntentService 源码中的 onCreate() 方法
- @Override
- public void onCreate() {
- super.onCreate();
- // HandlerThread 继承自 Thread, 内部封装了 Looper
- // 通过实例化 HandlerThread 新建线程并启动
- // 所以使用 IntentService 时不需要额外新建线程
- HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
- thread.start();
- // 获得工作线程的 Looper, 并维护自己的工作队列
- mServiceLooper = thread.getLooper();
- // 将上述获得 Looper 与新建的 mServiceHandler 进行绑定
- // 新建的 Handler 是属于工作线程的
- mServiceHandler = new ServiceHandler(mServiceLooper);
- }
- private final class ServiceHandler extends Handler {
- public ServiceHandler(Looper looper) {
- super(looper);
- }
- //IntentService 的 handleMessage 方法把接收的消息交给 onHandleIntent()处理
- //onHandleIntent()是一个抽象方法, 使用时需要重写的方法
- @Override
- public void handleMessage(Message msg) {
- // onHandleIntent 方法在工作线程中执行, 执行完调用 stopSelf() 结束服务
- onHandleIntent((Intent)msg.obj);
- //onHandleIntent 处理完成后 IntentService 会调用 stopSelf() 自动停止
- stopSelf(msg.arg1);
- }
- }
- ////onHandleIntent()是一个抽象方法, 使用时需要重写的方法
- @WorkerThread
- protected abstract void onHandleIntent(Intent intent);
问题 2:IntentService 如何通过 onStartCommand()传递给服务 intent 被依次插入到工作队列中
- public int onStartCommand(Intent intent, int flags, int startId) {
- onStart(intent, startId);
- return mRedelivery ? START_REDELIVER_INTENT: START_NOT_STICKY;
- }
- public void onStart(Intent intent, int startId) {
- Message msg = mServiceHandler.obtainMessage();
- msg.arg1 = startId;
- // 把 intent 参数包装到 message 的 obj 中, 然后发送消息, 即添加到消息队列里
- // 这里的 Intent 就是启动服务时 startService(Intent) 里的 Intent
- msg.obj = intent;
- mServiceHandler.sendMessage(msg);
- }
- // 清除消息队列中的消息
- @Override public void onDestroy() {
- mServiceLooper.quit();
- }
总结
?
从上面源码可以看出, IntentService 本质是采用 Handler & HandlerThread 方式:
通过 HandlerThread 单独开启一个名为 IntentService 的线程
创建一个名叫 ServiceHandler 的内部 Handler
把内部 Handler 与 HandlerThread 所对应的子线程进行绑定
通过 onStartCommand()传递给服务 intent, 依次插入到工作队列中, 并逐个发送给 onHandleIntent()
通过 onHandleIntent()来依次处理所有 Intent 请求对象所对应的任务
因此我们通过复写方法 onHandleIntent(), 再在里面根据 Intent 的不同进行不同的线程操作就可以了
注意事项 工作任务队列是顺序执行的
如果一个任务正在 IntentService 中执行, 此时你再发送一个新的任务请求, 这个新的任务会一直等待直到前面一个任务执行完毕才开始执行
原因:
由于 onCreate() 方法只会调用一次, 所以只会创建一个工作线程;
当多次调用 startService(Intent) 时 (onStartCommand 也会调用多次) 其实并不会创建新的工作线程, 只是把消息加入消息队列中等待执行, 所以, 多次启动 IntentService 会按顺序执行事件
如果服务停止, 会清除消息队列中的消息, 后续的事件得不到执行
七使用场景
线程任务需要按顺序在后台执行的使用场景
最常见的场景: 离线下载
由于所有的任务都在同一个 Thread looper 里面来做, 所以不符合多个数据同时请求的场景
八对比
8.1 IntentService 与 Service 的区别
从属性 & 作用上来说
Service: 依赖于应用程序的主线程(不是独立的进程 or 线程)
不建议在 Service 中编写耗时的逻辑和操作, 否则会引起 ANR;
IntentService: 创建一个工作线程来处理多线程任务
Service 需要主动调用 stopSelft()来结束服务, 而 IntentService 不需要(在所有 intent 被处理完后, 系统会自动关闭服务)
8.2 IntentService 与其他线程的区别
IntentService 内部采用了 HandlerThread 实现, 作用类似于后台线程;
与后台线程相比,
IntentService 是一种后台服务
, 优势是: 优先级高(不容易被系统杀死), 从而保证任务的执行
对于后台线程, 若进程中没有活动的四大组件, 则该线程的优先级非常低, 容易被系统杀死, 无法保证任务的执行
九参考文章
https://github.com/LRH1993/android_interview/blob/master/android/basis/IntentService.md
来源: http://www.bubuko.com/infodetail-2500574.html