Service 是 Android 四大组件之一,用于后台运行,但由于 Service 依然运行在主线程,所以是不能直接进行耗时操作的。如果有耗时操作,还是需要放到子线程中,可以手动开启线程,也可以使用 Android 提供的一个非常简便的类 IntentService
。这个类的源码还是很简单的,本文分析一下它的实现。
在分析 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()
开启消息循环,这个方法里面有个无限循环不断从消息队列中取出消息,于是这个线程的消息系统便建立起来了。这些在上一篇文章中已经分析过。
搞清楚 HandlerThread
, IntentService
就很简单了。 IntentService
内部使用了 HandlerThread
。 IntentService
继承了 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
创建了 Handler
。 IntentService
的 handleMessage
方法把接收的消息交给 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中执行,此时你再发送一个新的任务请求,这个新的任务会一直等待直到前面一个任务执行完毕才开始执行。
正在执行的任务无法打断。