IntentService是Service类的子类,常用来在后台执行耗时的异步请求。我们不用去关心Service的创建和销毁的细节。也不用单独开线程,只管处理自己的任务,处理完过后系统会自动销毁该服务,启动IntentService的方式和普通Service相同,但是使用起来却极其简单。使用示例如下:
//自定义一个IntentService
public class MyService extends IntentService {
public MyService() {
super("MyService");
}
@Override
protected void onHandleIntent(Intent intent) {
String url=intent.getStringExtra("url");
//在这处理你的任务
//...
}
}
//启动IntentService
Intent intent= new Intent(this,MyService.class);
intent.putExtra("url","......");
startService(intent);
看完上面的基本概念后,你可能会产生如下疑问。
让我们带着疑问,再次去源码里探索吧。
初看这个名字,心里在想,难道是内部自带Handler的线程?笔者怀着好奇的心,点开了HandlerThread这个类。因为HandlerThread继承于Thread,于是反射性的找到了run
方法里面的源码进行研究,源码如下:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();//初始化Looper
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();//开启Looper无限循环
mTid = -1;//这句话永远执行不到,除非Looper被退出
}
果然如此,很常规的Looper
初始化。有Looper
,肯定会有Handler
,不然Looper
岂不是浪费了。但是在Looper.prepare();
和Looper.loop()
之间,并没有看到Handler
的踪影。笔者心想,莫非谷歌用了什么黑科技用法,于是快速把源码过了一遍。WTF!Handler
呢?并没有找到啊。既然没有,干嘛叫HandlerThread
,这名字取的只给1分。于是查看了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()仍然必须调用。
看到这里算是明白了,原来这个线程只是用来提供Looper的啊,以免我们在子线程中使用Handler过于麻烦。必须调用start是因为,Looper的初始化在run
方法内。使用示例如下:
//启动带Looper的线程
HandlerThread handlerThread=new HandlerThread("handlerThread");
handlerThread.start();
//初始化Handler
Handler handler=new Handler(handlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
// 在这里接收消息,这里的处理是在子线程中执行的。
}
};
handler.sendMessage(..)//发送消息
笔者心想,由于线程的不稳定性,handlerThread.getLooper()
会不会取到个空值啊。点进去一看,瞬间觉得自己想多了。可以看到,如果为空就将线程挂起等待,即时你手动唤醒,还有个while循环进行保障。
public Looper getLooper() {
//...
//省略部分源码
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
当Looper初始化完毕,就会唤醒等待的线程,唤醒方法就在run
方法中。
public void run() {
//...
//省略部分源码
Looper.prepare();//初始化Looper
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();//唤醒等待线程
}
//...
//省略部分源码
Looper.loop();//开启Looper无限循环
}
可以看出handlerThread.getLooper()
是个阻塞方法。
IntentService的用法,前面已经介绍过了,现在开始来梳理流程。
我们知道,只需在onHandleIntent
里面编写耗时任务,系统就会自动开启线程去处理,处理完毕后,自动销毁Service。这一过程,尤其显得格外人性化。
那么,IntentService内部流程是怎么样的?IntentService继承与Service,那我们就按照Service的生命周期来一步一步进行探索,由于源码比较简单,这里就快速过一遍。
@Override
public void onCreate() {
super.onCreate();
//启动带Looper的线程
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//初始化Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
可以看出,用了HandlerThread
,同时也初始化了一个Handler
。看完这里。我想你心里一定有谱了。大约明白了内部工作原理。通过HandlerThread
,利用Handler
发送消息转移到子线程中,然后处理任务。
为了验证我们的猜想。继续阅读源码,找到onStartCommand
。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
可以看出,内部调用了onStart
。
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
在onStart
内部,终于验证了我们的猜想。将intent
和startId
,发送到了子线程中。于是我们找到Handler内部的handleMessage方法一探究竟。
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);
}
}
看到这里,终于明白了onHandleIntent
为什么不需再开线程。也明白了为什么可以自动销毁Service。
但是,机智的你可能心里在嘀咕。那个HandlerThread
呢?里面是个死循环,不能自动停止,一直占有着资源怎么办?那么。我们再来看一下Service的最后一个生命周期。
@Override
public void onDestroy() {
mServiceLooper.quit();
}
可以看出,在销毁的同时也退出了Looper
循环。
"Thread-" + id;
,不方便调试。 public IntentService(String name) {
super();
mName = name;
}
@Override
public void onCreate() {
//..
//省略了部分源码
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//..
//省略了部分源码
}
onHandleIntent
中退出Looper? stopSelf(int startId)
并不能结束服务。因为startId
必须与最后一次启动相同时才会结束服务。所以在onDestory中退出更加合适。可以看出在IntentService的内部又出现了Handler的身影,Handler在Android中的地位不言而喻,对于Handler不太了解的,可以参考这篇 Handler消息机制 源码解读。