1

简介

Service 是 Android 四大组件之一,用于后台运行,但由于 Service 依然运行在主线程,所以是不能直接进行耗时操作的。如果有耗时操作,还是需要放到子线程中,可以手动开启线程,也可以使用 Android 提供的一个非常简便的类 IntentService。这个类的源码还是很简单的,本文分析一下它的实现。

HandlerThread

在分析 IntentService 之前,先要了解 HandlerThread。看名字就知道这个类是与 Handler 有关的线程类,API 是这么描述的:

Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.

它是为创建附带 Looper 对象的线程的帮助类。Looper 对象可用于创建 Handler 类。 当然仍然要调用 start() 来开启线程。

在上篇文章 Android Handler的原理 中,我们知道一个线程创建 Handler 的时候,必须要有 Looper 对象,利用 Looper 开启消息循环。在主线程中,系统已经帮我们做了这些工作。那么如果在其它子线程,我们该怎么创建 Looper 呢? 看看 HandlerThread 的 run() 方法:

public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

在这个方法中调用了 Looper.prepare() 为线程获取 Looper 对象,并且保存这个对象。接着又调用 Looper.loop() 开启消息循环,这个方法里面有个无限循环不断从消息队列中取出消息,于是这个线程的消息系统便建立起来了。这些在上一篇文章中已经分析过。

IntentService

搞清楚 HandlerThreadIntentService 就很简单了。IntentService 内部使用了 HandlerThreadIntentService 继承了 Service 并且是 一个抽象类。下面是它的 onCreate() 方法:

 public void onCreate() {
    // TODO: It would be nice to have an option to hold a partial wakelock
    // during processing, and to have a static startService(Context, Intent)
    // method that would launch the service & hand off a wakelock.

    super.onCreate();
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();

    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
}

private final class ServiceHandler extends Handler {
    public ServiceHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        onHandleIntent((Intent)msg.obj);
        stopSelf(msg.arg1);
    }
}

这个方法里面创建了一个 HandlerThread 对象,并且获取它的 Looper,紧接着用这个 Looper 创建了 HandlerIntentServicehandleMessage方法把接收的消息交给 onHandleIntent 处理,这个方法是一个抽象方法,也是我们使用 IntentService 时需要重写的方法。onHandleIntent 处理完成后 IntentService会调用 stopSelf() 自动停止。handleMessage 将在 Looper.loop() 方法中被调用,运行在 HandlerThread 中,所以可以安全地处理耗时操作。

消息又是怎么传过来的呢?看一下 onStartCommand() 的源码:

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;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}

很简单,把 intent 参数包装到 message 的 obj 中,然后发送消息。这里的 Intent 就是启动服务时 startService(Intent) 里的 Intent

对于 Service 而言,多次调用 startService(Intent) 时,onCreate() 方法只会调用一次,所以在这里面做一些初始化工作,而 onStartCommand 则相应地会调用多次。因此,只要 Intent 的参数不同,便可以完成不同的任务。

总结

从上面的分析可以看出,只要明白 Handler 的原理,IntentService 还是比较好理解的。使用 IntentService 需要注意几点:

  • 不可以直接和UI做交互。为了把它执行的结果体现在UI上,需要把结果返回给Activity。
  • 工作任务队列是顺序执行的,如果一个任务正在IntentService中执行,此时你再发送一个新的任务请求,这个新的任务会一直等待直到前面一个任务执行完毕才开始执行。
  • 正在执行的任务无法打断。

如果我的文章对您有帮助,不妨点个赞鼓励一下(^_^)


然则
1.2k 声望415 粉丝