目錄:
Android的消息機(jī)制(異步處理)組成
- Message
- Handler
- 消息隊(duì)列MessageQueue
- Looper
AsyncTask
Looper與Handler的關(guān)系(關(guān)鍵)
AsyncTask和Handler對(duì)比
RxAndroid
Android異步處理組成
- Message
- Handler
- MessageQueue
- Looper
Message
在線程之間傳遞的消息怎静,可以在內(nèi)部攜帶少量的信息泞辐,用于在不同線程之間交換數(shù)據(jù)校赤。比如,在Activity中
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//這里處理發(fā)過來的信息
if (msg.what == 1){
//收到對(duì)應(yīng)的信息開始程序控制邏輯
Log.d(TAG,"收到風(fēng)篙梢,開始bb");
}
}
};
然后發(fā)送信息
Message message = new Message();
message.what = 1;
mHandler.sendMessage(message);
下面是Message能攜帶的信息類型
Handler
處理者缅叠,只要用于發(fā)送和處理信息。
發(fā)送消息一般用Handler的sendMessage方法欢顷,有時(shí)候會(huì)用帶有AtTime的mHandler.sendMessageAtTime()等方法定時(shí)發(fā)送實(shí)現(xiàn)定時(shí)啟動(dòng)某些功能或更新ui的的功能。最終消息傳到Handler的handleMessage方法處理
消息隊(duì)列MessageQueue
主要用于存放所有通過Handler發(fā)送的的消息捉蚤。這部分消息一直存放于消息隊(duì)列中抬驴,等待被處理炼七。重要的是,每個(gè)線程
只會(huì)有一個(gè)MessageQueue對(duì)象布持。
Looper
它是每個(gè)線程中MessageQueue的管家豌拙,這個(gè)是很重要的,當(dāng)調(diào)用Looper的loop()方法后题暖,就會(huì)進(jìn)入到一個(gè)無限循環(huán)中按傅,然后 每當(dāng)發(fā)現(xiàn)消息隊(duì)列中存在一條消息就取出,并傳遞到Handler的handleMessage()方法中胧卤。每個(gè)線程只會(huì)有一個(gè)Looper對(duì)象
流程
- 首先唯绍,在主線程中創(chuàng)建一個(gè)Handler對(duì)象,重寫handleMessage方法枝誊。
- 當(dāng)主線程需要進(jìn)行UI操作(比如播放器更新SeekBar)况芒,就創(chuàng)建一個(gè)Message對(duì)象,通過Handler把消息發(fā)送出去叶撒。之后這條消息將會(huì)被添加到消息隊(duì)列等待被處理绝骚,并且Looper會(huì)一直嘗試從消息隊(duì)列中取出待處理消息,最后發(fā)到Handler的handleMessage()方法中祠够。
Handler是在主線程中創(chuàng)建的皮壁,所以handleMessage()方法中的代碼也會(huì)在主線程中運(yùn)行。這樣就不用擔(dān)心子線程UI操作出錯(cuò)
Android也封裝了上面這個(gè)流程
runOnUiThread(new Runnable() {
@Override
public void run() {
}
});
AsyncTask
Android為了方便我們?cè)谧泳€程中對(duì)UI進(jìn)行操作哪审,提供的工具。原理也是基于上面的異步消息處理機(jī)制流程虑瀑。嗯湿滓,其實(shí)就是封裝的意思。
基本用法
class AsyncTaskDemo extends AsyncTask<Params, Progress, Result>{
//四個(gè)重載方法
}
上面的AsyncTask類總共有三個(gè)范型
- Params 執(zhí)行AsyncTask時(shí)傳入的參數(shù)舌狗,一般用于在后臺(tái)任務(wù)中使用
- Progress 后臺(tái)任務(wù)如果需要進(jìn)度叽奥,使用這里指定的范型作為進(jìn)度的單位。
- Result 任務(wù)處理完成后痛侍,如果需要返回結(jié)果朝氓,使用這里的范型作為返回值類型
AsyncTask的重載方法
onPreExecute()
在后臺(tái)任務(wù)執(zhí)行前開始調(diào)用,用于界面上的初始化等主届,比如顯示進(jìn)度條對(duì)話框doInBackground(Params...)
這里的代碼會(huì)之執(zhí)行在子線程赵哲,可以在這里處理所有的耗時(shí)任務(wù),任務(wù)完成可以通過return語句來返回任務(wù)的執(zhí)行結(jié)果君丁,特殊情況下枫夺,AsyncTask的第一個(gè)范型為Void,則不返回任務(wù)的執(zhí)行結(jié)果绘闷。
警告:這里不能進(jìn)行UI操作橡庞,如果需要反饋當(dāng)前任務(wù)的執(zhí)行進(jìn)度较坛,調(diào)用publishProgress(Progress...)來完成-
onProgressUpdate(Progress...)
在這里對(duì)UI進(jìn)行操作
當(dāng)在doInBackground(Params...)執(zhí)行了publishProgress(Progress...)方法后,這個(gè)方法就會(huì)被調(diào)用扒最,看參數(shù)是一樣的丑勤,就是
publishProgress(Progress...)傳過來的 -
onPostExecute(Result)
后臺(tái)任務(wù)執(zhí)行結(jié)束時(shí)被調(diào)用,Result是doInBackground(Params...)返回的數(shù)據(jù)吧趣,我們可以在這里進(jìn)行最后的UI工作法竞,比如,關(guān)閉進(jìn)度條窗口
全部的就像這樣
/**
* @param Void 后臺(tái)任務(wù)返回空值 doInBackground()
* @param Integer 有進(jìn)度條再菊,用這個(gè)作為進(jìn)度顯示單位 onProgressUpdate()
* @param Boolean 用布爾型數(shù)據(jù)反饋執(zhí)行結(jié)果 onPostExecute
* */
class AsyncTaskDemo extends AsyncTask<Void, Integer, Boolean>{
@Override
protected Boolean doInBackground(Void... params) {
// 后臺(tái)處理耗時(shí)任務(wù)爪喘,比如下載,這里有進(jìn)度
publishProgress(Progress...);//這個(gè)方法把進(jìn)度發(fā)到onProgressUpdate()處理了
return null;
}
@Override
protected void onPreExecute() {
// 顯示進(jìn)度對(duì)話框纠拔,任務(wù)開始前
}
@Override
protected void onPostExecute(Boolean aBoolean) {
//任務(wù)完成時(shí)調(diào)用秉剑,可以響應(yīng)任務(wù)結(jié)束的邏輯(用Result操作)
//關(guān)閉進(jìn)度條框
}
@Override
protected void onProgressUpdate(Integer... values) {
//更新UI,比如進(jìn)度條值
}
}
最后
new AsyncTaskDemo().execute();
就啟動(dòng)任務(wù)了
Looper與Handler的關(guān)系
轉(zhuǎn)載自 詳解Handler和Looper的關(guān)系
Handler
A Handler allows you to send and process Message
and Runnable objects associated with a thread's MessageQueue
. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
Looper
Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare()
in the thread that is to run the loop, and then loop()
to have it process messages until the loop is stopped.
Most interaction with a message loop is through the Handler
class.
Handler就是從消息隊(duì)列中拿出消息,Looper是負(fù)責(zé)遍歷和拿取消息隊(duì)列內(nèi)的消息的
Looper源碼
public class Looper {
// 每個(gè)線程中的Looper對(duì)象其實(shí)是一個(gè)ThreadLocal稠诲,即線程本地存儲(chǔ)(TLS)對(duì)象
private static final ThreadLocal sThreadLocal = new ThreadLocal();
// Looper內(nèi)的消息隊(duì)列
final MessageQueue mQueue;
// 當(dāng)前線程
Thread mThread;
// 侦鹏。。臀叙。其他屬性
// 每個(gè)Looper對(duì)象中有它的消息隊(duì)列略水,和它所屬的線程
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
// 我們調(diào)用該方法會(huì)在調(diào)用線程的TLS中創(chuàng)建Looper對(duì)象
public static final void prepare() {
if (sThreadLocal.get() != null) {
// 試圖在有Looper的線程中再次創(chuàng)建Looper將拋出異常
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
// 其他方法
}
可以看到Looper的構(gòu)造函數(shù)Looper()被聲明為private,也就是說劝萤,在外部渊涝,我們不能直接的使用Looper的構(gòu)造函數(shù)。所以床嫌,它這么創(chuàng)建Looper對(duì)象跨释,看下面
public static final void prepare() {
if (sThreadLocal.get() != null) {
// 試圖在有Looper的線程中再次創(chuàng)建Looper將拋出異常 ,只能有一個(gè)
throw new RuntimeException("Only one Looper may be created per thread");
}
//創(chuàng)建Looper對(duì)象
sThreadLocal.set(new Looper());
}
這個(gè)方法系統(tǒng)會(huì)在ThreadLocal內(nèi)添加一個(gè)Looper對(duì)象厌处,并且只能有一個(gè)Looper對(duì)象鳖谈,接著
public static final void loop() {
Looper me = myLooper(); //得到當(dāng)前線程Looper
MessageQueue queue = me.mQueue; //得到當(dāng)前l(fā)ooper的MQ
// 這兩行沒看懂= = 不過不影響理解
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// 開始循環(huán)
while (true) {
Message msg = queue.next(); // 取出message
if (msg != null) {
if (msg.target == null) {
// message沒有target為結(jié)束信號(hào),退出循環(huán)
return;
}
// 日志阔涉。缆娃。。
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
// 非常重要瑰排!將真正的處理工作交給message的target贯要,即后面要講的handler
msg.target.dispatchMessage(msg);
// 還是日志。椭住。郭毕。
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
// 下面沒看懂,同樣不影響理解
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf("Looper", "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);
}
// 回收message資源
msg.recycle();
}
}
}
當(dāng)我們調(diào)用Looper.loop()這個(gè)方法后函荣,Looper才真正的開始工作
Looper me = myLooper(); //得到當(dāng)前線程Looper
MessageQueue queue = me.mQueue; //得到當(dāng)前l(fā)ooper的MQ
獲取到當(dāng)前Looper的MessageQueue显押,每一個(gè)Looper都有一個(gè)消息隊(duì)列扳肛,并且這個(gè)消息隊(duì)列作為L(zhǎng)ooper的一個(gè)成員屬性。
然后再while內(nèi)循環(huán)這個(gè)消息隊(duì)列乘碑,不斷的取出數(shù)據(jù)
Message msg = queue.next(); // 取出message
判斷該消息隊(duì)列是否到結(jié)尾
if (msg != null)
if (msg.target == null) {
// message沒有target為結(jié)束信號(hào)挖息,退出循環(huán)
return;
}
最后注意下
looper()里有一句很關(guān)鍵
msg.target.dispatchMessage(msg)
其實(shí)是調(diào)用了
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//這里
handleMessage(msg);
}
}
恩。關(guān)鍵在handleMessage(msg);很熟悉吧
AsyncTask和Handler對(duì)比
AsyncTask
- 優(yōu)點(diǎn):簡(jiǎn)單兽肤,快捷套腹,過程可控
- 缺點(diǎn):使用多個(gè)異步操作并進(jìn)行UI變更時(shí),將會(huì)變復(fù)雜
Handler
- 優(yōu)點(diǎn):結(jié)構(gòu)清晰资铡,功能定義明確电禀,適合多個(gè)后臺(tái)任務(wù),
- 缺點(diǎn):?jiǎn)蝹€(gè)后臺(tái)異步處理笤休,代碼過多(相對(duì)AsyncTask)
RxAndroid
....恕我直言尖飞,不是針對(duì)上面某一個(gè)人........
RxAndroid:上面的Handler。AsyncTask都是辣雞
優(yōu)點(diǎn):可以更好的處理內(nèi)存泄露問題, 代碼也更加優(yōu)雅和可讀, 選擇執(zhí)行線程和監(jiān)聽線程也更加方便店雅。
建設(shè)中政基。插眼
Handler與AsyncTask參考自郭霖《第一行代碼》
晚安