IntentService分析
我所有的文章都會送出到github上,喜歡的同學可以來github關注。歡迎送出你們的文章
Github https://github.com/twolight/LearnNote.git
郵箱 [email protected]
背景
Service運作在調用它的程序和線程中,在開發當中,在Activity中啟動Service,意味着Service将運作在主線程中。是以,它的onXxx方法,并不能做耗時的操作的,不然将阻塞主線程,可能導緻ARN。
一般情況,在Service做耗時操作,會在Service中另開子線程,做這部分耗時操作。幸運的是,Android提供了IntenService這個類,滿足了我們在Service中做耗時操作的要求。
分析
下面将分析IntenService内部是如何做到的。下面是主要的代碼
public abstract class IntentService extends Service{
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);
}
}
@Override
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);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@WorkerThread
protected abstract void onHandleIntent(Intent intent);
}
在IntenService onCreate方法中,建立一個HandlerThread 線程對象并啟動起來。
看看HandlerThread的實作
public class HandlerThread extends Thread{
...
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -;
}
...
}
HandlerThread 确實是一個線程,果然IntentService實作也是另外開一個線程。
在這個子線程中啟動、運作的時候,建立一個Looper,并讓Loop開始從消息隊列取出消息進行處理。
public static void loop() {
...
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);
}
}
Looper的loop方法中,for無限循環的調用消息,通過注釋//might block,如果消息隊列為空,那麼線程會阻塞在這裡,直到有消息隊列不為空。取出來的消息如果為null,通過注釋// No message indicates that the message queue is quitting.。知道message queue正在退出,Looper就跳出循環,不在處理消息。不為null,則調用Hander的dispatchMessage方法。
Looper/Handler知識,請看我的另外一篇文章
Looper Handler MessageQueue分析
IntentService onCreate方法中,啟動啟動線程之後,獲得這個子線程的Looper,并且将它與ServiceHandler這個Handler綁定。
那我們就知道了,ServiceHandler其實是用來向子線程發送消息的。子線程通過Looper,去周遊消息隊列,取出消息,回調ServiceHandler的handleMessage方法,進而調用onHandleIntent方法。onHandleIntent方法,就是需要我們自己實作的耗時操作。
總結
-
IntentService建立時
建立一個Hander和子線程,handler與子線程的Looper綁定。線程run方法中,Looper一直循環等待處理消息。是以子線程不會退出,一直等待消息的到來。
-
IntentService啟動時
通過Handler向子線程發送消息,子線程周遊消息隊列,發現有消息,并處理消息,調用handleMessage方法,handleMessage方法調用onHandleIntent方法。onHandleIntent方法中我們實作自己的耗時操作。也就是說耗時操作,是在子線程運作的,并不會阻塞主線程。另外,onHandleIntent調用完接着會調用stopSelf(msg.arg1)方法,停止IntentService。系統回調onDestroy方法,讓子線程的Looper退出,不在循環處理消息。子線程的run方法也就調用完畢,子線程自己結束釋放線程資源。