IntentService源码解析

832 阅读4分钟

一、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的本质是采用HandlerHandlerThread的方式实现。

  • 创建一个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是一种后台服务,优势是:优先级高(不容易被系统杀死),从而保证任务的执行。

    对于后台线程,若进程中没有活动的四大组件,则该线程的优先级非常低,容易被系统杀死,无法保证任务的执行