一.HandlerThread的使用與原理解析
??HandlerThread繼承于Thread,所以它本質(zhì)就是個Thread。與普通Thread的差別就在于,它不僅建立了一個線程该押,并且創(chuàng)立了消息隊列,有自己的looper,可以讓我們在自己的線程中分發(fā)和處理消息阵谚,并對外提供自己這個Looper對象的get方法蚕礼。
??HandlerThread自帶Looper使他可以通過消息隊列烟具,來重復(fù)使用當(dāng)前線程,節(jié)省系統(tǒng)資源開銷奠蹬。這是它的優(yōu)點也是缺點朝聋,每一個任務(wù)都將以隊列的方式逐個被執(zhí)行到,一旦隊列中有某個任務(wù)執(zhí)行時間過長罩润,那么就會導(dǎo)致后續(xù)的任務(wù)都會被延遲處理玖翅。
1.HandlerThread使用步驟
第一步:創(chuàng)建HandlerThread實例對象
HandlerThread handlerThread = new HandlerThread("myThread");
第二步:啟動HandlerThread線程
handlerThread.start();
第三步:構(gòu)建循環(huán)消息處理機制
private Handler.Callback mSubCallback = new Handler.Callback() {
//該接口的實現(xiàn)就是處理異步耗時任務(wù)的,因此該方法執(zhí)行在子線程中
@Override
public boolean handleMessage(Message msg) {
//doSomething 處理異步耗時任務(wù)的
mUIHandler.sendMessage(msg1); //向UI線程發(fā)送消息割以,用于更新UI等操作
}
};
第四步:構(gòu)建子線程中的Handler:
//由于這里已經(jīng)獲取了workHandle.getLooper()金度,因此這個Handler是在HandlerThread線程也就是子線程中
childHandler = new Handler(handlerThread.getLooper(), mSubCallback);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//發(fā)送異步耗時任務(wù)到HandlerThread中,也就是上面的mSubCallback中
childHandler.sendMessage(msg);
}
});
第五步:構(gòu)建UI線程Handler處理消息(如果需要更新UI的話有這一步)
private Handler mUIHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
//在UI線程中做的事情,比如設(shè)置圖片什么的
}
};
2.HandlerThread的實現(xiàn)原理
??HandlerThread的實現(xiàn)原理比較簡單严沥,源碼也比較少(只有150行代碼)猜极,首先它是繼承自Thread類的:
public class HandlerThread extends Thread {
因此它完全可以當(dāng)一個線程來使用,就像上面我們說的:new HandlerTread().start()這樣消玄,但是8!翩瓜!——我們之前在Android中的消息機制——Looper受扳、Handler、MessageQueue與Message這篇文章中說過兔跌,在子線程中創(chuàng)建一個Handler勘高,需要手動創(chuàng)建Looper,即先Looper.parpare()坟桅,完了再Looper.loop()
這樣华望,我們來看看HandlerThread中的run方法:
@Override
public void run() {
mTid = Process.myTid(); //獲得當(dāng)前線程的id
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
//發(fā)出通知,當(dāng)前線程已經(jīng)創(chuàng)建mLooper對象成功仅乓,這里主要是通知getLooper方法中的wait
notifyAll();
}
//設(shè)置當(dāng)前線程的優(yōu)先級
Process.setThreadPriority(mPriority);
//該方法實現(xiàn)體是空的赖舟,子類可以實現(xiàn)該方法,作用就是在線程循環(huán)之前做一些準(zhǔn)備工作夸楣,當(dāng)然子類也可以不實現(xiàn)宾抓。
onLooperPrepared();
Looper.loop();
mTid = -1;
}
可以看到,這個run方法里邊寫死了豫喧,先Looper.prepare()然后Looper.loop()洞慎,也即是說,我們的HandlerThread這個特殊的“線程”是再帶Looper的嘿棘,因此——我們不能再主線程使用它劲腿,畢竟主線程是自帶MainLooper的,一個線程只能有一個Looper,否則就會拋出異常鸟妙。
??這里我們說一下焦人,為什么要看這個run()方法挥吵,之前我們在Android中的線程形態(tài)(一)(進程/線程/線程池)中有講過,Thread工作的時候花椭,不論哪種實現(xiàn)方法忽匈,我們都必須重寫這個類的run()方法,在其中寫我們自己要做的事情矿辽〉ぴ剩可以看到,HandlerThread類的run()方法已經(jīng)給我們寫死了袋倔,這就注定我們只能將它用在子線程中雕蔽。
??我們再來看看HandelerThread類的額另一個重要的方法——getLooper():
//該方法主要作用是獲得當(dāng)前HandlerThread線程中的mLooper對象
public Looper getLooper() {
if (!isAlive()) { //如果線程不是活動的,則直接返回null
return null;
}
// If the thread has been started, wait until the looper has been created.
//如果線程已經(jīng)啟動宾娜,但是Looper還未創(chuàng)建的話批狐,就等待,直到Looper創(chuàng)建成功
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
//這里會調(diào)用wait方法去等待前塔,當(dāng)run方法中的notifyAll方法調(diào)用之后
//通知當(dāng)前線程的wait方法等待結(jié)束嚣艇,跳出循環(huán),獲得mLooper對象的值华弓。
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
OK,看到這里食零,結(jié)合上面的HandelrThread使用步驟,我們需要總結(jié)一下:
- HandelrThread是一個自帶Looper的線程寂屏,因此只能作為子線程使用
- HandlerThread必須配合Handler使用慌洪,HandlerThread線程中做具體事情,必須要在Handler的callback接口中進行凑保,他自己的run方法被寫死了。
- 子線程中的Handler與HandlerThread的聯(lián)系是通過
childHandler = new Handler(handlerThread.getLooper(), mSubCallback);
這句來進行的涌攻,也就是你說欧引,childHandler獲得HandlerThread線程的Looper,這樣恳谎,他們兩個就在同一陣營了芝此。這也就是在創(chuàng)建Handler作為HandlerThread線程消息執(zhí)行者,必須在調(diào)用start()方法之后的原因——HandlerThread.start()之后因痛,run()方法才能跑起來婚苹,Looper才能得以創(chuàng)建,handlerThread.getLooper()
才不會出錯鸵膏。
二.IntentService的使用與實現(xiàn)原理
??HandlerThread在Android中的一個具體的應(yīng)用就是IntentService膊升。IntentService是繼承于Service并處理異步請求的一個類。注意這句話——“繼承于Service”和“處理異步請求”谭企。“繼承于Service”表示他是一個服務(wù)廓译,我們知道Service是存在于主線程的评肆,它之中不能存在耗時操作,否則的話回應(yīng)起ANR非区,因此便有了IntentService——這個封裝了HandlerThread和Handler的特殊Service瓜挽。
1.IntentService的使用
第一步:創(chuàng)建一個繼承IntentService類的子類
首先,通過源碼我們知道征绸,IntentService是一個繼承自Service類的抽象類久橙,因此我們必須創(chuàng)建一個繼承它的子類才能實現(xiàn)相關(guān)功能:
public class MyIntentService extends IntentService {
public ServiceUpdate() {
// 注意構(gòu)造函數(shù)參數(shù)為空,這個myIntentService字符串就是IntentService中工作線程的名字
super("myIntentService");
}
//打印生命周期
@Override
public void onCreate() {
Log.i("myIntentService", "onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("myIntentService", "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onStart(Intent intent, int startId) {
Log.i("myIntentService", "onStart");
super.onStart(intent, startId);
}
@Override
public IBinder onBind(Intent intent) {
Log.i("myIntentService", "onBind");
return super.onBind(intent);
}
//重寫onHandleIntent方法管怠,在該方法中進行我們的各種事務(wù)處理
@Override
protected void onHandleIntent(Intent intent) {
//一般Intent是從Activity發(fā)過來的淆衷,攜帶識別參數(shù),根據(jù)參數(shù)不同執(zhí)行不同的任務(wù)
String taskName = intent.getExtras().getString("taskName");
switch (taskName) {
case "task1":
Log.i("myIntentService", "task1");
break;
case "task2":
Log.i("myIntentService", "task2");
break;
default:
break;
}
}
@Override
public void onDestroy() {
Log.i("myIntentService", "onDestroy");
super.onDestroy();
}
}
第二步:在Activity中開啟服務(wù):
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
......
//同一服務(wù)只會開啟一個工作線程排惨,在onHandleIntent函數(shù)里依次處理intent請求吭敢。
Intent intent1 = new Intent(this,MyIntentService.class);
Bundle bundle = new Bundle();
bundle.putString("taskName", "task1");
intent1.putExtras(bundle);
startService(intent1);
Intent intent2 = new Intent(this,MyIntentService.class);
Bundle bundle2 = new Bundle();
bundle2.putString("taskName", "task2");
intent2.putExtras(bundle2);
startService(intent2);
}
}
第三步:在 Manifest 中注冊服務(wù)
<service android:name=".service.MyIntentService"/>
上述過程中我們啟動了兩個IntentService服務(wù),打印出來生命周期為:onCreate -> onStartCommand -> onStart -> onStartCommand -> onStart -> task1 -> task2 -> onDestroy暮芭,OnBinder沒有執(zhí)行鹿驼。
??從結(jié)果可以看到,onCreate 方法只執(zhí)行了一次辕宏,而 onStartCommand 和 onStart 方法執(zhí)行了兩次畜晰,開啟了兩個 工作線程(Work Thread),這就證實了之前所說的瑞筐,啟動多次凄鼻,但IntentService 的實例只有一個,這跟傳統(tǒng)的Service 是一樣的聚假。
2.IntentServic源碼分析
??IntentService繼承Service類之后块蚌,整體的源碼也就165行,跟HandlerThread差不多膘格,我們先來看看它的實例變量:
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper; //服務(wù)所在線程的Looper
private volatile ServiceHandler mServiceHandler; //構(gòu)建一個服務(wù)中的Handler
private String mName; //服務(wù)所在線程的名字
private boolean mRedelivery;
1).IntentService的構(gòu)造方法
上面加了注釋的三個變量較為重要峭范,我們待會會一步步分析。接下來我們看看他的構(gòu)造方法:
public IntentService(String name) {
super();
mName = name;
}
可以看到瘪贱,上線例子中我們得
public ServiceUpdate() {
super("myIntentService");
}
其中“myIntentService”實際會上傳到父類IntentService的構(gòu)造方法中纱控,也就是IntentService所在線程的線程名字,IntentService構(gòu)造方法中的super();
又會進一步調(diào)用Service類中的構(gòu)造函數(shù):
public Service() {
super(null);
}
再網(wǎng)上菜秦,就到ContextWrapper類里邊去了甜害。如果我們看過Activity的源碼的話就會知道,Activity也是繼承自ContextWrapper類的球昨,而ContextWrapper類繼承自Context尔店!也就說,Service和Activity實際上都是一個Context!ContextWrapper有一個比較特殊的地方是闹获,他的實例化的地方是在ActivityThread中由系統(tǒng)完成的期犬,我們無權(quán)插手。因此避诽,在StartService或者StartActivity的時候龟虎,系統(tǒng)就會自動幫我們實例化這兩個組件。這樣沙庐,Service的構(gòu)造方法為空也就很好解釋了鲤妥。
2).OnCreat()
??看上面的生命周期流程圖我們知道,IntentService第一步指定的onCreat方法:
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
首先拱雏,super.onCreate();
棉安,這個我們看到Service的onCreat()方法是空的,所以不管铸抑,接著看贡耽。HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
看到了吧,這里重量級人物——HandlerThread出場了鹊汛,新建了一個HandlerThread實例蒲赂,上面我們說過HandlerThread()的構(gòu)造方法傳進去的是HandlerThread所在線程的名字,然后thread.start();
刁憋,嗯滥嘴,非常符合我們上半片文章講的HandlerThread使用流程。
??mServiceLooper = thread.getLooper();
這里通過mServiceLooper獲取到HandlerThread線程的Looper至耻。然后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);
}
}
可以看到,ServiceHandler是IntentService類的一個內(nèi)部類尘颓,并且繼承自Handler走触,重寫了handleMessage方法。很顯然疤苹,這個類是用來處理startService(intent);
傳遞來的消息的互广。這個消息處理的過程分為兩步,第一調(diào)用onHandleIntent((Intent)msg.obj);
方法痰催;第二步stopSelf(msg.arg1);
消息處理完后自動終止服務(wù)。所以我們接著而看onHandleIntent((Intent)msg.obj);
:
@WorkerThread
protected abstract void onHandleIntent(Intent intent);
呦呵迎瞧?這是一個抽象方法夸溶,抽象類中的抽象方法意味著我們需要在子類中重寫這個方法,也就是說凶硅,這個方法才是我們處理消息的地方缝裁。可以看到,這個方法上面加了注解捷绑,是位于工作線程(子線程)中的韩脑。
3).onStartCommand()/onStart()
??好了,OnCreat()方法終于執(zhí)行完了粹污,onStartCommand()方法段多,它和onStart()方法實際上是連在一起的:
@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) {
//Service 啟動后直接就向 mServiceHandler 發(fā)送消息,則馬上就會執(zhí)行 handleMessage方法
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
這個方法中壮吩,mServiceHandler這個Handler的子類进苍,調(diào)用了obtainMessage()方法,該方法實際上上到Handler類中調(diào)用的是:
public final Message obtainMessage(){
return Message.obtain(this);
}
這個方法中鸭叙,Message.obtain(this);
這個方法我們復(fù)習(xí)一下觉啊,實際上就是Handler從消息池中取出一個消息,避免Message類重復(fù)創(chuàng)建的一個方法沈贝「苋耍回到IntentSerice的onStart()方法中,Message msg = mServiceHandler.obtainMessage();
宋下,這句就是獲取一個Message對象嗡善,然后mServiceHandler.sendMessage(msg);
通過Handler發(fā)送消息,添加到Looper中的MessageQuenue隊列中杨凑。
4).onDestroy()
@Override
public void onDestroy() {
mServiceLooper.quit();
}
安全退出Looper()
3.IntentService中的一些坑
1).為什么不建議通過 bindService() 啟動 IntentService滤奈?
@Override
public IBinder onBind(Intent intent) {
return null;
}
??IntentService 源碼中的 onBind() 默認返回 null;不適合 bindService() 啟動服務(wù)撩满,如果你執(zhí)意要 bindService() 來啟動 IntentService蜒程,可能因為你想通過 Binder 或 Messenger 使得 IntentService 和 Activity 可以通信,這樣那么 onHandleIntent() 不會被回調(diào)伺帘,相當(dāng)于在你使用 Service 而不是 IntentService昭躺。
2).為什么多次啟動 IntentService 會順序執(zhí)行事件,停止服務(wù)后伪嫁,后續(xù)的事件得不到執(zhí)行领炫?
??IntentService 中使用的 Handler、Looper张咳、MessageQueue 機制把消息發(fā)送到線程中去執(zhí)行的帝洪,所以多次啟動 IntentService 不會重新創(chuàng)建新的服務(wù)和新的線程,只是把消息加入消息隊列中等待執(zhí)行脚猾,而如果服務(wù)停止葱峡,會清除消息隊列中的消息,后續(xù)的事件得不到執(zhí)行龙助。
站在巨人的肩膀上摘蘋果:
IntentService 示例與詳解
Service 和 IntentService 的區(qū)別等