一、IntentService简介
IntentService is a base class for {@link Service}s that handle asynchronous requests (expressed as {@link Intent}s) on demand. Clients send requests through {@link android.content.Context#startService(Intent)} calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
IntentService是继承自Service用来处理异步请求的一个基类,客户端startService发送请求,IntentService就被启动,然后会在一个工作线程中处理传递过来的Intent,当任务结束后就会自动停止服务。
1.IntentService使用场景
- 线程任务需要按照顺序在后台执行的使用场景,例如:离线下载
- 由于所有的任务都是在同一个
HandlerThread里面来做,不符合多个数据同事请求的场景。
2.IntentService简单使用
- 步骤1:定义
IntentService的子类:传入线程名称、复写onHandleIntent()方法 - 步骤2:在
AndroidManifest.xml中注册服务 - 步骤3:在
Activity中开启Service服务
class MyIntentService extends IntentService {
public MyIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
// 处理耗时操作
}
}
// 启动
startService(new Intent(this,MyIntentService.class));
我们不需要关心Service的生命周期,IntentService会自行处理。
二、IntentService源码分析
1.成员变量
private volatile Looper mServiceLooper; // 子线程中的Looper
private volatile ServiceHandler mServiceHandler; // 内部持有一个Handler
private String mName; // 内部创建线程的名称
private boolean mRedelivery; // 服务被异常终止后重新创建调用onStartCommand是否回传Intent
2.构造方法
public IntentService(String name) {
super();
mName = name; //
}
3.onCreate()方法
@Override
public void onCreate() {
super.onCreate();
// HandlerThread继承自Thread,内部封装了Looper,
// 通过实例化HandlerThread并启动线程
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
// 获得工作线程的Looper,并维护自己的工作队列
mServiceLooper = thread.getLooper();
// 创建工作线程的Handler
mServiceHandler = new ServiceHandler(mServiceLooper);
}
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// onHandleIntent 方法在工作线程中执行,执行完调用 stopSelf() 结束服务。
onHandleIntent((Intent)msg.obj);
// onHandleIntent 处理完成后 IntentService会调用 stopSelf() 自动停止。
stopSelf(msg.arg1);
}
}
onHandleIntent()是一个抽象方法,使用时需要重写的方法,该方法执行在工作线程中。
由此可以知道IntentService是如何开启工作线程的。
4.onStartCommand()方法、onStart()方法
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
// 调用onStart()
onStart(intent, startId);
// 根据mRedelivery的值来确定返回重传Intent的黏性广播还是非黏性广播
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
// 创建一个Message
Message msg = mServiceHandler.obtainMessage();
// 消息标志,作为当前Service的标志,可用来停止Service
msg.arg1 = startId;
// 要处理的Intent
msg.obj = intent;
// 发送消息,此时将线程切换到工作线程中
mServiceHandler.sendMessage(msg);
}
//清除消息队列中的消息
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
public void handleMessage(Message msg) {
// 处理发送过来的消息,在子线程
onHandleIntent((Intent)msg.obj);
// 处理完消息之后停止Service
stopSelf(msg.arg1);
}
在onStart()方法中,mServiceHandler发送携带Intent的消息,将线程切换到工作线程中,此时消息就已经加入到工作队列中,然后在handleMessage()方法中处理消息。
由此我们可以知道,IntentService是如何通过onStartCommand()传递服务Intent,并依次插入到工作队列中。
三、总结
从源码中可以看出,IntentService的本质是采用Handler和HandlerThread的方式实现。
- 创建一个
HandlerThread,开启HandlerThread来创建Looper; - 创建一个
Handler,并传入已经创建好的Looper,从而在工作线程实例化Handler; - 在
onStartCommand()方法中获取Intent,并使用Handler将带有Intent的消息发送出去; - 然后在
onHandleIntent()方法中处理这个消息,注意此时已经切换到工作线程; - 和
HandlerThread一样,IntentService的任务也是串行执行的,所以也不适合大量的耗时操作。
四、对比
1.IntentService和Service的区别
Service依赖于应用程序的主线程,不建议在Service中编写耗时的操作,否则会引起ANR;IntentService,创建一个工作线程来处理多线程任务。
2.IntentService与其他工作线程的区别
IntentService内部采用了HandlerThread实现,作用类似于后台线程;- 与后台线程相比,
IntentService是一种后台服务,优势是:优先级高(不容易被系统杀死),从而保证任务的执行。对于后台线程,若进程中没有活动的四大组件,则该线程的优先级非常低,容易被系统杀死,无法保证任务的执行