基本概念
IntentService作用
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);
IntentService疑問
看完上面的基本概念後,你可能會産生如下疑問。
- IntentService構造方法傳的那個參數是來幹嘛的
- IntentService内部是怎麼工作的?
- IntentService怎麼做到任務結束後自動銷毀?
讓我們帶着疑問,再次去源碼裡探索吧。
初識API
HandlerThread
初看這個名字,心裡在想,難道是内部自帶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 = -;//這句話永遠執行不到,除非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的生命周期來一步一步進行探索,由于源碼比較簡單,這裡就快速過一遍。
onCreate
@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
為了驗證我們的猜想。繼續閱讀源碼,找到
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方法一探究竟。
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的最後一個生命周期。
onDestroy
@Override
public void onDestroy() {
mServiceLooper.quit();
}
可以看出,在銷毀的同時也退出了
Looper
循環。
最後
-
IntentService構造方法傳的那個參數是來幹嘛的
我們先來看一下IntentService的構造函數。可以看出最終傳給了HandlerThread。而給Thread傳一個名字更加便于調試,不然線程的預設名是
,不友善調試。"Thread-" + id;
public IntentService(String name) {
super();
mName = name;
}
@Override
public void onCreate() {
//..
//省略了部分源碼
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//..
//省略了部分源碼
}
- 為什麼不在
onHandleIntent
中退出Looper?
那是因為跟普通Service一樣,IntentService也可以啟動多次。如果在結束服務之前又有新任務送出過來了,
并不能結束服務。因為stopSelf(int startId)
必須與最後一次啟動相同時才會結束服務。是以在onDestory中退出更加合适。startId
總結
可以看出在IntentService的内部又出現了Handler的身影,Handler在Android中的地位不言而喻,對于Handler不太了解的,可以參考這篇 Handler消息機制 源碼解讀。