1.0異步消息處理機(jī)制
Android中的異步消息處理主要由4個(gè)部分組成:Message、Handler、MessageQueue和Looper。
- Message:是在線程之間傳遞的消息,Message的what字段可以在內(nèi)部攜帶少量的信息,用于在不同線程之間傳遞數(shù)據(jù)。除此之外還可以使用arg1和arg2字段來攜帶一些整型數(shù)據(jù),使用obj字段攜帶一個(gè)Object對(duì)象。
- HandlerHandler:是處理者,它主要是用于發(fā)送和處理消息的。發(fā)送消息一般是使用Handler的sendMessage()方法、post()方法等,而發(fā)出的消息經(jīng)過一系列地輾轉(zhuǎn)處理后,最終會(huì)傳遞到Handler的handleMessage()方法中。
- MessageQueue:是消息隊(duì)列,它主要用于存放所有通過Handler發(fā)送的消息。這部分消息會(huì)一直存在于消息隊(duì)列中,等待被處理。每個(gè)線程中只會(huì)有一個(gè)MessageQueue對(duì)象。
- LooperLooper:是每個(gè)線程中的MessageQueue的管家,調(diào)用Looper的loop()方法后,就會(huì)進(jìn)入一個(gè)無限循環(huán)當(dāng)中,然后每當(dāng)發(fā)現(xiàn)MessageQueue中存在一條消息時(shí),就會(huì)將它取出,并傳遞到Handler的handleMessage()方法中。每個(gè)線程中只會(huì)有一個(gè)Looper對(duì)象。
異步消息處理的整個(gè)流程如下:
- 首先需要在主線程當(dāng)中創(chuàng)建一個(gè)Handler對(duì)象,并重寫handleMessage()方法。
- 然后當(dāng)子線程中需要進(jìn)行操作時(shí),就創(chuàng)建一個(gè)Message對(duì)象,并通過Handler將這條消息發(fā)送出去。
- 之后這條消息會(huì)被添加到MessageQueue的隊(duì)列中等待被處理,而Looper則會(huì)一直嘗試從MessageQueue中取出待處理消息。
- 最后分發(fā)回Handler的handleMessage()方法中。
由于Handler的構(gòu)造函數(shù)中傳入了Looper.getMainLooper(),所以此時(shí)handleMessage()方法中的代碼也會(huì)在主線程中運(yùn)行。
整個(gè)異步消息處理機(jī)制的流程如圖所示。

1.1異步消息處理應(yīng)用
Android是不允許在子線程中進(jìn)行UI操作的。但是有些時(shí)候,我們必須在子線程里執(zhí)行一些耗時(shí)任務(wù),然后根據(jù)任務(wù)的執(zhí)行結(jié)果來更新相應(yīng)的UI控件,這該如何是好呢?
對(duì)于這種情況,使用上文提到的異步消息處理機(jī)制,可以完美地解決了在子線程中進(jìn)行UI操作的問題。
代碼如下:

2.0AsyncTask
Android提供了AsyncTask,借助AsyncTask,即使對(duì)異步消息處理機(jī)制完全不了解,也可以十分簡(jiǎn)單地從子線程切換到主線程。AsyncTask背后的實(shí)現(xiàn)原理也是基于異步消息處理機(jī)制的,只是Android幫做了很好的封裝。
AsyncTask是一個(gè)抽象類,必須創(chuàng)建一個(gè)子類去繼承它。在繼承時(shí)可以為AsyncTask類指定3個(gè)泛型參數(shù),這3個(gè)參數(shù)的用途如下。
- Params。在執(zhí)行AsyncTask時(shí)需要傳入的參數(shù),可用于在后臺(tái)任務(wù)中使用。
- Progress。在后臺(tái)任務(wù)執(zhí)行時(shí),如果需要在界面上顯示當(dāng)前的進(jìn)度,則使用這里指定的泛型作為進(jìn)度單位。
- Result。當(dāng)任務(wù)執(zhí)行完畢后,如果需要對(duì)結(jié)果進(jìn)行返回,則使用這里指定的泛型作為返回值類型。
因此,一個(gè)最簡(jiǎn)單的自定義AsyncTask就可以寫成如下形式:

- 第一個(gè)泛型參數(shù)指定為Unit,表示在執(zhí)行AsyncTask的時(shí)候不需要傳入?yún)?shù)給后臺(tái)任務(wù)。
- 第二個(gè)泛型參數(shù)指定為Int,表示使用整型數(shù)據(jù)來作為進(jìn)度顯示單位。
- 第三個(gè)泛型參數(shù)指定為Boolean,則表示使用布爾型數(shù)據(jù)來反饋執(zhí)行結(jié)果。
還需要重寫AsyncTask中的幾個(gè)方法才能完成對(duì)任務(wù)的定制。經(jīng)常需要重寫的方法有以下4個(gè)。
- onPreExecute()這個(gè)方法會(huì)在后臺(tái)任務(wù)開始執(zhí)行之前調(diào)用,用于進(jìn)行一些界面上的初始化操作,比如顯示一個(gè)進(jìn)度條對(duì)話框等。
- doInBackground(Params...)這個(gè)方法中的所有代碼都會(huì)在子線程中運(yùn)行,應(yīng)該在這里去處理所有的耗時(shí)任務(wù)。任務(wù)一旦完成,就可以通過return語句將任務(wù)的執(zhí)行結(jié)果返回,如果AsyncTask的第三個(gè)泛型參數(shù)指定的是Unit,就可以不返回任務(wù)執(zhí)行結(jié)果。注意,在這個(gè)方法中是不可以進(jìn)行UI操作的,如果需要更新UI元素,比如說反饋當(dāng)前任務(wù)的執(zhí)行進(jìn)度,可以調(diào)用publishProgress (Progress...)方法來完成。
- onProgressUpdate(Progress...)當(dāng)在后臺(tái)任務(wù)中調(diào)用了publishProgress(Progress...)方法后,onProgressUpdate(Progress...)方法就會(huì)很快被調(diào)用,該方法中攜帶的參數(shù)就是在后臺(tái)任務(wù)中傳遞過來的。在這個(gè)方法中可以對(duì)UI進(jìn)行操作,利用參數(shù)中的數(shù)值就可以對(duì)界面元素進(jìn)行相應(yīng)的更新。
因此,一個(gè)比較完整的自定義AsyncTask就可以寫成如下形式:

如果想要啟動(dòng)這個(gè)任務(wù),只需編寫以下代碼即可:
