系列文章
Android面試攻略(1)——Android基礎(chǔ)
Android面試攻略(2)——異步消息處理機(jī)制
Android面試攻略(3)——View相關(guān)
本篇文章主要涉及Handler、AsyncTask、HandlerThread、IntentService
Handler
一、什么是Handler
當(dāng)程序第一次啟動(dòng)的時(shí)候,Android會(huì)同時(shí)啟動(dòng)一條主線程( Main Thread)來負(fù)責(zé)處理與UI相關(guān)的事件,我們叫做UI線程。
Android的UI操作并不是線程安全的(出于性能優(yōu)化考慮),意味著如果多個(gè)線程并發(fā)操作UI線程,可能導(dǎo)致線程安全問題。
為了解決Android應(yīng)用多線程問題—Android平臺(tái)只允許UI線程修改Activity里的UI組建,就會(huì)導(dǎo)致新啟動(dòng)的線程無法改變界面組建的屬性值。
簡(jiǎn)單的說:當(dāng)主線程隊(duì)列處理一個(gè)消息超過5秒,android 就會(huì)拋出一個(gè) ANP(無響應(yīng))的異常,所以,我們需要把一些要處理比較長(zhǎng)的消息,放在一個(gè)單獨(dú)線程里面處理,把處理以后的結(jié)果,返回給主線程運(yùn)行,就需要用的Handler來進(jìn)行線程建的通信。
handler通過發(fā)送和處理Message和Runnable對(duì)象來關(guān)聯(lián)相對(duì)應(yīng)的線程的MessageQueue。可以讓對(duì)應(yīng)的Message和Runnable在未來的某個(gè)時(shí)間點(diǎn)進(jìn)行相應(yīng)的處理(延時(shí)處理:postAtTime()、postDelayed())。讓自己想要處理的耗時(shí)操作放在子線程,讓更新ui的操作放在主線程。
二、Handler的基本使用
- 首先聲明一個(gè)Handler,復(fù)寫其handleMessage方法
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what == 1)
mTextView.setText("更新UI");
}
};
- 在子線程發(fā)送消息通知Handler執(zhí)行操作
new Thread() {
@Override
public void run() {
super.run();
//do something ...
//子線程中通過handler發(fā)送消息給handler接收,由handler去更新TextView的值
Message msg = Message.obtain();
msg.what = 1;
msg.obj = "需要發(fā)送的數(shù)據(jù)";
mHandler.sendMessage(msg);
}
}.start();
三、Handler原理分析
首先我們來想看下Handler的構(gòu)造方法
public Handler();
public Handler(Callback callback);
public Handler(Looper looper);
public Handler(Looper looper, Callback callback);
前兩個(gè)構(gòu)造方法是沒有傳遞Looper對(duì)象的,這兩個(gè)方法內(nèi)部會(huì)調(diào)用另一個(gè)構(gòu)造方法
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
可以看到,這個(gè)構(gòu)造方法通過Looper.myLooper()獲取了保存在該線程下的mLooper實(shí)例對(duì)象,再通過mLopper.mQueue獲取了MessageQueue。也就是每個(gè)Handler 對(duì)應(yīng)一個(gè)Looper對(duì)象,產(chǎn)生一個(gè)MessageQueue。那其實(shí)我們并沒有做過Looper的保存操作,為什么這里可以拿到保存的Looper呢?其實(shí),我們這里獲取到的Looper,是主線程創(chuàng)建的時(shí)候,實(shí)現(xiàn)了Looper的兩個(gè)重要的方法。我們來看下ActivtyThread.class中的源碼:
public static final void main(String[] args) {
// -----
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
// ----
}
首先我們來看Looper.prepareMainLooper(),其內(nèi)部調(diào)用了prepare(false)
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
該方法保證了Looper的唯一性且會(huì)調(diào)用Looper構(gòu)造函數(shù)同時(shí)實(shí)例化出MessageQueue和當(dāng)前thread.
public static @NonNull MessageQueue myQueue() {
return myLooper().mQueue;
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
prepare()方法中通過ThreadLocal對(duì)象實(shí)現(xiàn)Looper實(shí)例與線程的綁定,即保存當(dāng)前的Looper實(shí)例到ThreadLocal當(dāng)中,Handler中通過Looper.myLooper()將Looper實(shí)例從ThreadLocal中取出。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
Handler、Looper、MessageQueue都有了,下面該發(fā)送消息了,我們看看Handle發(fā)送消息的幾個(gè)方法源碼
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what) {
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
可以看到,它們最終都調(diào)用了sendMessageAtTime()方法,然后返回了enqueueMessage(),我們來看看這個(gè)方法的源碼
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
在該方法中有兩件事需要注意:
- msg.target = this:該代碼將Message的target綁定為當(dāng)前的Handler
- queue.enqueueMessage :變量queue表示的是Handler所綁定的消息隊(duì)列MessageQueue,通過調(diào)用queue.enqueueMessage(msg, uptimeMillis)我們將Message放入到消息隊(duì)列中。
消息放入消息隊(duì)列之后,怎么處理呢?我們最后來看下loop()方法
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
首先looper對(duì)象不能為空,就是說loop()方法調(diào)用必須在prepare()方法的后面。
Looper一直在不斷的從消息隊(duì)列中通過MessageQueue的next方法獲取Message,然后通過代碼msg.target.dispatchMessage(msg)讓該msg所綁定的Handler(Message.target)執(zhí)行dispatchMessage方法以實(shí)現(xiàn)對(duì)Message的處理。
Handler的dispatchMessage的源碼如下:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
我們可以看到Handler提供了三種途徑處理Message,而且處理有前后優(yōu)先級(jí)之分:首先嘗試讓postXXX中傳遞的Runnable執(zhí)行,其次嘗試讓Handler構(gòu)造函數(shù)中傳入的Callback的handleMessage方法處理,最后才是讓Handler自身的handleMessage方法處理Message。
Callback參數(shù):Callback是Handler中的內(nèi)部接口,需要實(shí)現(xiàn)其內(nèi)部的handleMessage方法,Callback代碼如下:
public interface Callback {
public boolean handleMessage(Message msg);
}
Handler.Callback是用來處理Message的一種手段,如果沒有傳遞該參數(shù),那么就應(yīng)該重寫Handler的handleMessage方法,也就是說為了使得Handler能夠處理Message,我們有兩種辦法:
- 向Hanlder的構(gòu)造函數(shù)傳入一個(gè)Handler.Callback對(duì)象,并實(shí)現(xiàn)Handler.Callback的handleMessage方法。
- 無需向Hanlder的構(gòu)造函數(shù)傳入Handler.Callback對(duì)象,但是需要重寫Handler本身的handleMessage方法 。
也就是說無論哪種方式,我們都得通過某種方式實(shí)現(xiàn)handleMessage方法,這點(diǎn)與Java中對(duì)Thread的設(shè)計(jì)有異曲同工之處。
四、在子線程中使用Handler
我們知道,在子線程中使用Handler會(huì)出錯(cuò),為什么?
Handler本質(zhì)是從當(dāng)前的線程中獲取到Looper來監(jiān)聽和操作MessageQueue,當(dāng)其他線程執(zhí)行完成后回調(diào)當(dāng)前線程。而子線程中并沒有預(yù)先設(shè)置Looper,所以導(dǎo)致Handler調(diào)用Looper.myLooper()時(shí)找不到Looper對(duì)象導(dǎo)致拋出異常。所以,我們?nèi)绻朐谧泳€程中使用,必須在聲明Handler之前,調(diào)用Looper.prepare(),然后調(diào)用Looper的loop()方法來啟動(dòng)Looper讓消息隊(duì)列轉(zhuǎn)動(dòng)起來。
class DownLoadThread implements Runnable {
public Handler myHandler;
// 實(shí)現(xiàn)Runnable接口的線程體
@Override
public void run() {
/*①、調(diào)用Looper的prepare()方法為當(dāng)前線程創(chuàng)建Looper對(duì)象并,
創(chuàng)建Looper對(duì)象時(shí),它的構(gòu)造器會(huì)自動(dòng)的創(chuàng)建相對(duì)應(yīng)的MessageQueue*/
Looper.prepare();
/*.②、創(chuàng)建Handler子類的實(shí)例,重寫HandleMessage()方法,該方法處理除當(dāng)前線程以外線程的消息*/
myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
String ms = "";
if (msg.what == 0x777) {
}
}
};
//③、調(diào)用Looper的loop()方法來啟動(dòng)Looper讓消息隊(duì)列轉(zhuǎn)動(dòng)起來
Looper.loop();
}
}
五、Handler引起的內(nèi)存泄漏以及解決辦法
原因:靜態(tài)內(nèi)部類持有外部類的匿名引用,導(dǎo)致外部Activity無法釋放。
解決辦法:1. Handler內(nèi)部持有外部Activity的弱引用。2. 把Handler改為靜態(tài)內(nèi)部類。3. 在Activity的onDestroy()方法中調(diào)用mHandler.removeCallback()。
AsyncTask
一、什么是AsyncTask
AsyncTask本質(zhì)上就是一個(gè)封裝了線程池和Handler的異步框架。適用于簡(jiǎn)單的異步處理。
二、基本使用
繼承AsyncTask類實(shí)現(xiàn)自己的類,并重寫其中的方法。
三個(gè)參數(shù)
public abstract class AsyncTask<Params, Progress, Result> {}
Params: 輸入?yún)?shù),對(duì)應(yīng)excute()方法中傳遞的參數(shù)。如果不需要傳遞參數(shù),則直接設(shè)為void即可。
Progress:后臺(tái)任務(wù)執(zhí)行的百分比
Result:返回值類型,和doInBackground()方法的返回值類型保持一致。
五個(gè)方法
protected abstract Result doInBackground(Params... params);
protected void onPostExecute(Result result) {
}
protected void onProgressUpdate(Progress... values) {
}
protected void onPreExecute() {
}
protected void onCancelled() {
}
最少要重寫以下這兩個(gè)方法:
doInBackground(Params…)
在子線程(其他方法都在主線程執(zhí)行)中執(zhí)行比較耗時(shí)的操作,不能更新UI,可以在該方法中調(diào)用publishProgress(Progress…)來更新任務(wù)的進(jìn)度。Progress方法是AsycTask中一個(gè)final方法只能調(diào)用不能重寫。onPostExecute(Result)
使用在doInBackground 得到的結(jié)果處理操作UI, 在主線程執(zhí)行,任務(wù)執(zhí)行的結(jié)果作為此方法的參數(shù)返回。 有時(shí)根據(jù)需求還要實(shí)現(xiàn)以下三個(gè)方法:onProgressUpdate(Progress…)
可以使用進(jìn)度條增加用戶體驗(yàn)度。 此方法在主線程執(zhí)行,用于顯示任務(wù)執(zhí)行的進(jìn)度。onPreExecute()
這里是最終用戶調(diào)用Excute時(shí)的接口,當(dāng)任務(wù)執(zhí)行之前開始調(diào)用此方法,可以在這里顯示進(jìn)度對(duì)話框。onCancelled()
用戶調(diào)用取消時(shí),要做的操作
在主線程中申明該類的對(duì)象,調(diào)用對(duì)象的execute()函數(shù)開始執(zhí)行。
MyAsyncTask t = new MyAsyncTask();
t.execute();
三、AsyncTask的機(jī)制原理
- AsyncTask的本質(zhì)是一個(gè)靜態(tài)的線程池,AsyncTask派生出的子類可以實(shí)現(xiàn)不同的異步任務(wù),這些任務(wù)都是提交到靜態(tài)的線程池中執(zhí)行。
- 線程池中的工作線程執(zhí)行doInBackground方法執(zhí)行異步任務(wù)。
- 當(dāng)任務(wù)狀態(tài)改變后,工作線程會(huì)向UI線程發(fā)送消息,AsyncTask內(nèi)部的InternalHandler響應(yīng)這些消息,并調(diào)用相關(guān)的回調(diào)函數(shù)。
四、AsyncTask的注意事項(xiàng)
AsyncTask不適合特別耗時(shí)的任務(wù)
AsyncTask的生命周期和Activity的生命周期不同步,Activity銷毀了但是AsyncTask中的任務(wù)還是會(huì)繼續(xù)執(zhí)行完畢,一個(gè)最典型的例子就是Activity的橫豎屏切換,AsyncTask中引用的Activity不是當(dāng)前的Activity,onPostExecute()中執(zhí)行的仍然是上一個(gè)Activity。還有一個(gè)原因是因?yàn)锳syncTask在執(zhí)行長(zhǎng)時(shí)間的耗時(shí)任務(wù)時(shí)也會(huì)持有一個(gè)Activity對(duì)象,即使這個(gè)Activity已經(jīng)不可見了,Android也無法對(duì)這個(gè)Activity進(jìn)行回收,導(dǎo)致內(nèi)存泄露。AsyncTask只能在主線程中創(chuàng)建以及使用
AsyncTask被用于執(zhí)行異步任務(wù),然后更新UI,所以最后的onPostExecute()方法執(zhí)行在創(chuàng)建該AsyncTask對(duì)象的線程中,如果不在主線程中創(chuàng)建以及使用,就達(dá)不到更新UI的目的。一個(gè)AsyncTask對(duì)象只能執(zhí)行一次
一個(gè)AsyncTask對(duì)象只能執(zhí)行一次,即只能調(diào)用一次execute方法,否則會(huì)報(bào)運(yùn)行時(shí)異常AsyncTask。這是源碼注釋中寫的,但是我查閱資料也沒有找到什么具體原因。本人學(xué)藝也不精...也就知道了不能重復(fù)對(duì)一個(gè)AsyncTask對(duì)象調(diào)用execute()方法。AsyncTask在不同的Android版本下的并行和串行問題
關(guān)于AsyncTask的并行和串行問題,在不同的API下是有不同的。在Android1.6之前,AsyncTask是串行執(zhí)行任務(wù)的;到了Android1.6時(shí),開始采用線程池來并行執(zhí)行任務(wù);在Android3.0之后的版本中,AsyncTask又開始用一個(gè)線程串行執(zhí)行任務(wù)。雖然Android3.0之后采用串行方式執(zhí)行任務(wù),但我們可以通過AsyncTask的executeOnExecutor(exe,params),自定義一個(gè)線程池來并行執(zhí)行任務(wù)。
HandlerThread
一、什么是HandlerThread
當(dāng)我們需要執(zhí)行耗時(shí)操作時(shí),很自然的會(huì)想到開啟一個(gè)子線程,當(dāng)耗時(shí)操作完成之后,線程自動(dòng)銷毀。之后如果我們又需要執(zhí)行另一個(gè)耗時(shí)操作,再開啟一個(gè)子線程,這時(shí)就涉及到一個(gè)性能問題了。要知道,頻繁的創(chuàng)建和銷毀線程是很耗費(fèi)系統(tǒng)資源的,所以,為了解決這個(gè)問題,Android給我們提供了HandlerThread這個(gè)類。
好吧,其實(shí)初看這段話,我是沒搞懂HandlerThread到底是干啥的,所以我們來看看它的用法先吧。
二、HandlerThread的用法
HandlerThread的使用十分簡(jiǎn)單,簡(jiǎn)單到只有幾行代碼
HandlerThread ht = new HandlerThread("newThread");
ht.start();
mHandler = new Handler(ht.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//do something
}
};
聲明一個(gè)HandlerThread對(duì)象并傳入一個(gè)字符串參數(shù),然后調(diào)用start()方法啟動(dòng)HandlerThread,將HandlerThread里的Looper傳入Handler。最后記得在Activity的onDestroy()方法中將HandlerThread關(guān)閉
@Override
protected void onDestroy() {
super.onDestroy();
//釋放資源
ht.quit() ;
}
用法很簡(jiǎn)單,但是為什么要這么用?這樣子聲明的Handler跟平時(shí)我們用的有什么不一樣呢,那我們來看看HandlerThread的源碼。
三、HandlerThread的源碼分析
HandlerThread的源碼不多,首先來看下類的繼承關(guān)系
public class HandlerThread extends Thread {}
HandlerThread 繼承自Thread,也就是說HandlerThread 本質(zhì)就是一個(gè)線程類,所以當(dāng)我們new HandlerThread ()的時(shí)候?qū)嶋H上是創(chuàng)建了一個(gè)子線程所以之后調(diào)用了start()方法啟動(dòng)了該線程,那接下來我們來看下關(guān)鍵的run()方法
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
run()方法里面調(diào)用了Looper.prepare()和Looper.loop(),這個(gè)過程是不是很眼熟,我們前面說過了在子線程中使用Handler,需要自己調(diào)用這兩個(gè)方法,而我們?cè)诼暶鱄andler時(shí),將這個(gè)Looper對(duì)象通過getLooper()方法獲取到并作為參數(shù)傳入了進(jìn)去
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
如果你夠細(xì)心你會(huì)發(fā)現(xiàn),run方法里面當(dāng)mLooper創(chuàng)建完成后有個(gè)notifyAll(),getLooper()中有個(gè)wait(),這是為什么呢?因?yàn)閙Looper在一個(gè)線程中執(zhí)行,而我們的handler是在UI線程初始化的,也就是說,我們必須等到mLooper創(chuàng)建完成,才能正確的返回getLooper();wait(),notify()就是為了解決這兩個(gè)線程的同步問題。
結(jié)合前面對(duì)Handler的分析,我們知道,當(dāng)我們需要在子線程與子線程之間進(jìn)行通信,也就是需要在子線程中使用Handler時(shí),需要手動(dòng)去操作Looper,這是很不推薦的做法。所以Google官方很貼心的幫我們封裝好了一個(gè)類,那就是剛才HandlerThread啦。
最后再來看看quit()方法
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
兩個(gè)方法最后都是調(diào)用MessageQueue里面的quit(boolean)方法
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
nativeWake(mPtr);
}
}
當(dāng)我們調(diào)用Looper的quit方法時(shí),實(shí)際上執(zhí)行了MessageQueue中的removeAllMessagesLocked方法,該方法的作用是把MessageQueue消息池中所有的消息全部清空,無論是延遲消息(延遲消息是指通過sendMessageDelayed或通過postDelayed等方法發(fā)送的需要延遲執(zhí)行的消息)還是非延遲消息。
當(dāng)我們調(diào)用Looper的quitSafely方法時(shí),實(shí)際上執(zhí)行了MessageQueue中的removeAllFutureMessagesLocked方法,通過名字就可以看出,該方法只會(huì)清空MessageQueue消息池中所有的延遲消息,并將消息池中所有的非延遲消息派發(fā)出去讓Handler去處理,quitSafely相比于quit方法安全之處在于清空消息之前會(huì)派發(fā)所有的非延遲消息。
無論是調(diào)用了quit方法還是quitSafely方法只會(huì),Looper就不再接收新的消息。即在調(diào)用了Looper的quit或quitSafely方法之后,消息循環(huán)就終結(jié)了,這時(shí)候再通過Handler調(diào)用sendMessage或post等方法發(fā)送消息時(shí)均返回false,表示消息沒有成功放入消息隊(duì)列MessageQueue中,因?yàn)橄㈥?duì)列已經(jīng)退出了。
四、HandlerThread的特點(diǎn)
- HandlerThread的本質(zhì)依然是一個(gè)線程類,它繼承自Thread。
- HandlerThread有自己的內(nèi)部Looper對(duì)象,可以進(jìn)行l(wèi)ooper循環(huán)。
- 通過獲取HandlerThread的looper對(duì)象傳遞給Handler對(duì)象,可以在handleMessage方法中執(zhí)行異步任務(wù)。
- 優(yōu)點(diǎn)是不會(huì)阻塞,減少了對(duì)性能的消耗,缺點(diǎn)是不能同時(shí)進(jìn)行多任務(wù)的處理,需要等待進(jìn)行處理,處理效率低。
- 與線程池注重并發(fā)不同,HandleThread是一個(gè)串行隊(duì)列,HandlerThread背后只有一個(gè)線程。
IntentService
一、IntentService是什么
IntentService是繼承并處理異步請(qǐng)求的一個(gè)類,在IntentService內(nèi)有一個(gè)工作線程來處理耗時(shí)操作,啟動(dòng)IntentService的方式和傳統(tǒng)的Service一樣,同時(shí),當(dāng)任務(wù)執(zhí)行完后,IntentService會(huì)自動(dòng)停止,而不需要我們手動(dòng)去控制或者stopSelf()。另外,可以啟動(dòng)IntentService多次,而每一次耗時(shí)操作會(huì)以工作隊(duì)列的方式在IntentService的onHandleIntent回調(diào)方法中執(zhí)行,并且,每次只會(huì)執(zhí)行一個(gè)工作線程,執(zhí)行完第一個(gè)再執(zhí)行第二個(gè)。
- 它本質(zhì)是一種特殊的Service,繼承自Service并且本身就是一個(gè)抽象類。
- 它內(nèi)部通過HandlerThread和Handler實(shí)現(xiàn)異步操作。
二、IntentService的基本使用
繼承IntentService實(shí)現(xiàn)自己類,并重寫構(gòu)造函數(shù)和onHandleIntent()方法,onHandleIntent()是個(gè)異步方法,可以執(zhí)行耗時(shí)操作。
public class MyIntentService extends IntentService {
public static final String INDEX_FLAG = "index_flag";
public static UpdateUI updateUI;
public MyIntentService(String name) {
super(name);
}
public static void setUpdateUI(UpdateUI updateUIInterface) {
updateUI = updateUIInterface;
}
//運(yùn)行在子線程的方法,intent是從啟動(dòng)該服務(wù)的context傳過來的
@Override
protected void onHandleIntent(Intent intent) {
try {
Thread.sleep(5000);
Message msg = new Message();
msg.what = intent.getIntExtra(INDEX_FLAG, 0);
msg.obj = "返回的值" + msg.what;
if (updateUI != null)
updateUI.updateUI(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public interface UpdateUI {
void updateUI(Message message);
}
}
Activity中啟動(dòng)該服務(wù)并設(shè)置回調(diào)
public class MainActivity extends AppCompatActivity implements MyIntentService.UpdateUI {
private static TextView mTextView;
private static final Handler mUIHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mTextView.setText((String) msg.obj);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = findViewById(R.id.text);
Intent intent = new Intent(this, MyIntentService.class);
for (int i = 0; i < 7; i++) {
intent.putExtra(MyIntentService.INDEX_FLAG, i);
startService(intent);
}
MyIntentService.setUpdateUI(this);
}
@Override
public void updateUI(Message message) {
mUIHandler.sendMessageDelayed(message, message.what * 1000);
}
}
activity中循環(huán)啟動(dòng)了7次service,但實(shí)際只有一個(gè)IntentService實(shí)例,IntentService會(huì)依次執(zhí)行這7次操作,然后通過UpdateUI 接口回調(diào)結(jié)果更新UI。
三、IntentService的源碼解析
首先,還是看繼承關(guān)系
public abstract class IntentService extends Service {}
可以看到,IntentService本質(zhì)還是個(gè)Service,那我們就去看它的onCreate()方法
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
在onCreate()方法中,創(chuàng)建了一個(gè)HandlerThread實(shí)例對(duì)象并將它傳入了ServiceHandler對(duì)象中,ServiceHandler實(shí)際就是一個(gè)Handler,所以通過這一步,IntentService具備了進(jìn)行異步操作的能力。接著我們來看onStart()方法
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
在onStart()中,通過ServiceHandler發(fā)送了一條附帶startId和Intent的Message,最終這個(gè)Message會(huì)被發(fā)送到持有l(wèi)ooper的ServiceHandler的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);
}
}
handleMessage中執(zhí)行了onHandleIntent()這個(gè)方法,也就是我們繼承IntentService時(shí)需要重寫的抽象方法,所以onHandleIntent()是個(gè)異步方法,因?yàn)樗菆?zhí)行在HandlerThread開啟的子線程中的。
值得注意的一點(diǎn)是當(dāng)調(diào)用完onHandleIntent()之后ServiceHandler 調(diào)用了stopSelf(msg.arg1),這個(gè)方法跟stopSelf()的區(qū)別是stopSelf(msg.arg1)會(huì)判斷當(dāng)前的服務(wù)是不是最后的服務(wù),如果不是則不關(guān)閉,等最后的服務(wù)完成后才關(guān)閉,而stopSelf()會(huì)直接關(guān)閉服務(wù)。
所以,IntentService的本質(zhì)就是一個(gè)封裝了HandlerThread和Handler的異步框架。
參考資料
Android 異步消息處理機(jī)制(Handler 、 Looper 、MessageQueue)源碼解析
Android異步任務(wù)機(jī)制之AsycTask