HandlerThread
HandlerThread繼承了Thread答憔,它是一種可以使用Handler的Thread秕狰,它的實(shí)現(xiàn)也很簡(jiǎn)單哥纫,就是在run方法中通過(guò)Looper.prepare()來(lái)創(chuàng)建消息隊(duì)列脖镀,并通過(guò)Looper.loop()來(lái)開(kāi)啟消息循環(huán)麸塞,這樣在實(shí)際的使用中就允許在HandlerThread中創(chuàng)建Handler了。HandlerThread的run方法如下所示:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
從HandlerThread的實(shí)現(xiàn)來(lái)看椰憋,它和普通的Thread有顯著的不同之處波势。普通Thread主要用于在run方法中執(zhí)行一個(gè)耗時(shí)任務(wù),而HandlerThread在內(nèi)部創(chuàng)建了消息隊(duì)列笆檀,外界需要通過(guò)Handler的消息方式來(lái)通知HandlerThread執(zhí)行一個(gè)具體的任務(wù)忌堂。HandlerThread是一個(gè)很有用的類,它在Android中的一個(gè)具體的使用場(chǎng)景是IntentService酗洒。由于HandlerThread的run方法是一個(gè)無(wú)限循環(huán)士修,因此當(dāng)明確不需要再使用HandlerThread時(shí),可以通過(guò)它的quit或者quitSafely方法來(lái)終止線程的執(zhí)行樱衷,這是一個(gè)良好的編程習(xí)慣棋嘲。
11.2.4 IntentService
IntentService是一種特殊的Service,它繼承了Service并且它是一個(gè)抽象類矩桂,因此必須創(chuàng)建它的子類才能使用IntentService沸移。IntentService可用于執(zhí)行后臺(tái)耗時(shí)的任務(wù),當(dāng)任務(wù)執(zhí)行后它會(huì)自動(dòng)停止侄榴,同時(shí)由于IntentService是服務(wù)的原因雹锣,這導(dǎo)致它的優(yōu)先級(jí)比單純的線程要高很多,所以IntentService比較適合執(zhí)行一些高優(yōu)先級(jí)的后臺(tái)任務(wù)牲蜀,因?yàn)樗鼉?yōu)先級(jí)高不容易被系統(tǒng)殺死笆制。在實(shí)際上,IntentService封裝了HandlerThread和Handler涣达,這一點(diǎn)可以從它的onCreate方法中看出來(lái)在辆。
@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);
}
當(dāng)IntentService被第一次啟動(dòng)時(shí),它的onCreate()方法會(huì)被調(diào)用度苔,onCreate()方法會(huì)創(chuàng)建一個(gè)HandlerThread匆篓,然后使用它的Looper來(lái)構(gòu)造一個(gè)Handler對(duì)象mServiceLooper,這樣通過(guò)mServiceLooper發(fā)送的消息最終都會(huì)在HandlerThread中執(zhí)行寇窑,從這個(gè)角度來(lái)看鸦概,IntentService也可以用于執(zhí)行后臺(tái)任務(wù)。每次啟動(dòng)IntentService甩骏,它的onStartCommand方法就會(huì)調(diào)用一次窗市,IntentService在onStartCommand中處理每個(gè)后臺(tái)任務(wù)的Intent。下面看一下onStartCommand方法是如何處理外界的Intent的饮笛,onStartCommand調(diào)用了onStart咨察,onStart方法的實(shí)現(xiàn)如下所示:
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
IntentService僅僅是通過(guò)mServiceHandler發(fā)送了一個(gè)消息,這個(gè)消息會(huì)在HandlerThread中被處理福青。mServiceHandler收到消息后摄狱,會(huì)將Intent對(duì)象傳遞給onHandleIntent方法去處理脓诡。注意這個(gè)Intent對(duì)象的內(nèi)容和外界的startService(intent)中的intent的內(nèi)容是完全一致的,通過(guò)這個(gè)Intent對(duì)象即可解析出外界啟動(dòng)IntentService時(shí)所傳遞的參數(shù)媒役,通過(guò)這些參數(shù)就可以區(qū)分具體的后臺(tái)任務(wù)祝谚,這樣在onHandleIntent方法中就可以對(duì)不同的后臺(tái)任務(wù)做處理了。當(dāng)onHandleIntent方法執(zhí)行結(jié)束后酣衷,IntentService會(huì)通過(guò)stopSelf(int startId)方法來(lái)嘗試停止服務(wù)交惯。這里之所以采用stopSelf(int startId)而不是stopSelf()來(lái)停止服務(wù),那是因?yàn)閟topSelf()會(huì)立刻停止服務(wù)穿仪,而這個(gè)時(shí)候可能還有其他消息未處理商玫,stopSelf(int startId)則會(huì)等待所有的消息都處理完畢后才終止服務(wù)。一般來(lái)說(shuō)牡借,stopSelf(int startId)在嘗試停止服務(wù)之前會(huì)判斷最近啟動(dòng)服務(wù)的次數(shù)是否和startId相等拳昌,如果相等就立刻停止服務(wù),不相等則不停止服務(wù)钠龙,這個(gè)策略可以從AMS的stopServiceToken方法的實(shí)現(xiàn)中找到依據(jù)炬藤,感興趣的話可以自行查看源碼實(shí)現(xiàn)。
ServiceHandler的實(shí)現(xiàn)如下所示:
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);
}
}
IntentService的onHandleIntent方法是一個(gè)抽象方法碴里,它需要我們?cè)谧宇愔袑?shí)現(xiàn)沈矿,它的作用是從Intent參數(shù)中區(qū)分具體的任務(wù)并執(zhí)行這些任務(wù)。如果目前只存在一個(gè)后臺(tái)任務(wù)咬腋,那么onHandleIntent方法執(zhí)行完這個(gè)任務(wù)后羹膳,stopSelf(int startId)就會(huì)直接停止服務(wù),如果目前存在多個(gè)后臺(tái)任務(wù)根竿,那么當(dāng)onHandleIntent方法執(zhí)行完最后一個(gè)任務(wù)時(shí)陵像,stopSelf(int startId)才會(huì)直接停止服務(wù)。另外寇壳,由于每執(zhí)行一個(gè)后臺(tái)任務(wù)就必須啟動(dòng)一次IntentService醒颖,而IntentService內(nèi)部則通過(guò)消息的方式向HandlerThread請(qǐng)求執(zhí)行任務(wù),Handler中的Looper是順序處理消息的壳炎,這就意味著IntentService也是順序執(zhí)行后臺(tái)任務(wù)的泞歉,當(dāng)有多個(gè)后臺(tái)任務(wù)同時(shí)存在時(shí),這些后臺(tái)任務(wù)會(huì)按照外界發(fā)起的順序排隊(duì)執(zhí)行匿辩。
下面通過(guò)一個(gè)示例來(lái)進(jìn)一步說(shuō)明IntentService的工作方式腰耙,首先派生一個(gè)IntentService的子類。
public class LocalIntentService extends IntentService {
private static final String TAG = "LocalIntentService";
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public LocalIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
String action = intent.getStringExtra("task_action");
Log.d(TAG,"receive task :" + action);
SystemClock.sleep(3000);
if ("com.ryg.action.TASK1".equals(action)) {
Log.d(TAG,"handle task:" + action);
}
}
@Override
public void onDestroy() {
Log.d(TAG,"service destroyed.");
super.onDestroy();
}
}
在onHandleIntent方法中會(huì)從參數(shù)中解析出后臺(tái)任務(wù)的標(biāo)識(shí)铲球,即task_action字段所代表的內(nèi)容挺庞,然后根據(jù)不同的任務(wù)標(biāo)識(shí)來(lái)執(zhí)行具體的后臺(tái)任務(wù)。這里為了簡(jiǎn)單起見(jiàn)睬辐,直接通過(guò)SystemClock.sleep(3000)來(lái)休眠3000毫秒從而模擬一種耗時(shí)的后臺(tái)任務(wù)挠阁,另外為了驗(yàn)證IntentService的停止時(shí)機(jī),這里在onDestroy()中打印了一句日志溯饵。LocalIntentService實(shí)現(xiàn)完成了以后侵俗,就可以在外界請(qǐng)求執(zhí)行后臺(tái)任務(wù)了,在下面的代碼中先后發(fā)起了3個(gè)后臺(tái)任務(wù)的請(qǐng)求:
Intent service = new Intent(this,LocalIntentService.class);
service.putExtra("task_action","com.ryg.action.TASK1");
startService(service);
service.putExtra("task_action","com.ryg.action.TASK2");
startService(service);
service.putExtra("task_action","com.ryg.action.TASK3");
startService(service);
運(yùn)行程序丰刊,觀察日志隘谣,如下所示:
略
三個(gè)后臺(tái)任務(wù)是排隊(duì)執(zhí)行的,它們的執(zhí)行順序就是它們發(fā)起請(qǐng)求對(duì)的順序啄巧,即TASK1寻歧,TASK2,TASK3秩仆。另外一點(diǎn)就是當(dāng)TASK3執(zhí)行完畢后码泛,LocalIntentService才真正地停止,從日志中可以看出LocalIntentService執(zhí)行了onDestroy()澄耍,這也意味著服務(wù)正在停止噪珊。