7 Handler可以發(fā)送Messsage和Runnable對(duì)象到與其相關(guān)聯(lián)的線(xiàn)程的消息隊(duì)列。每個(gè)Handler對(duì)象與創(chuàng)建它的線(xiàn)程相關(guān)聯(lián),并且每個(gè)Handler對(duì)象只能與一個(gè)線(xiàn)程相關(guān)聯(lián)。 Handler一般有兩種用途:1)執(zhí)行計(jì)劃任務(wù),你可以再預(yù)定的實(shí)現(xiàn)執(zhí)行某些任務(wù),可以模擬定時(shí)器。2)線(xiàn)程間通信。在Android的應(yīng)用啟動(dòng)時(shí),會(huì) 創(chuàng)建一個(gè)主線(xiàn)程,主線(xiàn)程會(huì)創(chuàng)建一個(gè)消息隊(duì)列來(lái)處理各種消息。當(dāng)你創(chuàng)建子線(xiàn)程時(shí),你可以在你的子線(xiàn)程中拿到父線(xiàn)程中創(chuàng)建的Handler對(duì)象,就可以通過(guò)該 對(duì)象向父線(xiàn)程的消息隊(duì)列發(fā)送消息了。由于Android要求在UI線(xiàn)程中更新界面,因此,可以通過(guò)該方法在其它線(xiàn)程中更新界面。
◆ 通過(guò)Runnable在子線(xiàn)程中更新界面的例子 1.○ 在onCreate中創(chuàng)建Handler
public class HandlerTestApp extends Activity {
Handler mHandler;
TextView mText;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mHandler = new Handler();//創(chuàng)建Handler
mText = (TextView) findViewById(R.id.text0);//一個(gè)TextView
}
○ 構(gòu)建Runnable對(duì)象,在runnable中更新界面,此處,我們修改了TextView的文字.此處需要說(shuō)明的是,Runnable對(duì)象可以再主線(xiàn)程中創(chuàng)建,也可以再子線(xiàn)程中創(chuàng)建。我們此處是在子線(xiàn)程中創(chuàng)建的。
Runnable mRunnable0 = new Runnable()
{
@Override
public void run() {
mText.setText("This is Update from ohter thread, Mouse DOWN");
}
};
? ○ 創(chuàng)建子線(xiàn)程,在線(xiàn)程的run函數(shù)中,我們向主線(xiàn)程的消息隊(duì)列發(fā)送了一個(gè)runnable來(lái)更新界面。 private void updateUIByRunnable(){
new Thread()
{
//Message msg = mHandler.obtainMessage();
public void run()
{ //mText.setText("This is Update from ohter thread, Mouse DOWN");//這句將拋出異常
mHandler.post(mRunnable0);
}
}.start(); } ◆ 用Message在子線(xiàn)程中來(lái)更新界面 1. 用Message更新界面與Runnable更新界面類(lèi)似,只是需要修改幾個(gè)地方。
○ 實(shí)現(xiàn)自己的Handler,對(duì)消息進(jìn)行處理 private class MyHandler extends Handler
{ @Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what)
{
case UPDATE ://在收到消息時(shí),對(duì)界面進(jìn)行更新
mText.setText("This update by message");
break;
}
}
} ○ 在新的線(xiàn)程中發(fā)送消息
private void updateByMessage()
{
//匿名對(duì)象
new Thread()
{
public void run()
{
//mText.setText("This is Update from ohter thread, Mouse DOWN"); //UPDATE是一個(gè)自己定義的整數(shù),代表了消息ID
Message msg = mHandler.obtainMessage(UPDATE);
mHandler.sendMessage(msg);
}
}.start();
} AsyncTask與handler AsyncTask實(shí)際上就是一個(gè)線(xiàn)程池,AsyncTask在代碼上比handler要輕量級(jí)別,而實(shí)際上要比handler更耗資源,因?yàn)锳syncTask底層是一個(gè)線(xiàn)程池!而Handler僅僅就是發(fā)送了一個(gè)消息隊(duì)列,連線(xiàn)程都沒(méi)有開(kāi)。
但是,如果異步任務(wù)的數(shù)據(jù)特別龐大,AsyncTask這種線(xiàn)程池結(jié)構(gòu)的優(yōu)勢(shì)就體現(xiàn)出來(lái)了。 android的ui線(xiàn)程操作并不是安全的,并且和用戶(hù)直接進(jìn)行界面交互的操作都必須在ui線(xiàn)程中進(jìn)行才可以。這種模式叫做單線(xiàn)程模式。 我們?cè)趩尉€(xiàn)程模式下編程一定要注意:不要阻塞ui線(xiàn)程、確保只在ui線(xiàn)程中訪問(wèn)ui組件 當(dāng)我們要執(zhí)行一個(gè)復(fù)雜耗時(shí)的算法并且最終要將計(jì)算結(jié)果反映到ui上時(shí),我們會(huì)發(fā)現(xiàn),我們根本沒(méi)辦法同時(shí)保證上面的兩點(diǎn)要求;我們肯定會(huì)想到開(kāi)啟一個(gè)新的線(xiàn)程,讓這個(gè)復(fù)雜耗時(shí)的任務(wù)到后臺(tái)去執(zhí)行,但是執(zhí)行完畢了呢?我們發(fā)現(xiàn),我們無(wú)法再與ui進(jìn)行交互了。 為了解決這種情況,android為我們提供了很多辦法。 1)、handler和message機(jī)制:通過(guò)顯示的拋出、捕獲消息與ui進(jìn)行交互; 2)、Activity.runOnUiThread(Runnable):如果當(dāng)前線(xiàn)程為ui線(xiàn)程,則立即執(zhí)行;否則,將參數(shù)中的線(xiàn)程操作放入到ui線(xiàn)程的事件隊(duì)列中,等待執(zhí)行。 3)、View.post(Runnable):將操作放入到message隊(duì)列中,如果放入成功,該操作將會(huì)在ui線(xiàn)程中執(zhí)行,并返回true,否則返回false 4)、View.postDelayed(Runnable, long)跟第三條基本一樣,只不過(guò)添加了一個(gè)延遲時(shí)間。 5)、android1.5以后為我們提供了一個(gè)工具類(lèi)來(lái)搞定這個(gè)問(wèn)題AsyncTask. AsyncTask是抽象類(lèi),定義了三種泛型類(lèi)型 Params,Progress,Result。 Params 啟動(dòng)任務(wù)執(zhí)行的輸入?yún)?shù),比如HTTP請(qǐng)求的URL Progress 后臺(tái)任務(wù)執(zhí)行的百分比。 Result 后臺(tái)執(zhí)行任務(wù)最終返回的結(jié)果,比如String 用程序調(diào)用,開(kāi)發(fā)者需要做的就是實(shí)現(xiàn)這些方法。 1) 子類(lèi)化AsyncTask 2) 實(shí)現(xiàn)AsyncTask中定義的下面一個(gè)或幾個(gè)方法 ,該方法將在執(zhí)行實(shí)際的后臺(tái)操作前被UI thread調(diào)用??梢栽谠摲椒ㄖ凶鲆恍?zhǔn)備工作,如在界面上顯示一個(gè)進(jìn)度條。 ,將在onPreExecute 方法執(zhí)行后馬上執(zhí)行,該方法運(yùn)行在后臺(tái)線(xiàn)程中。這里將主要負(fù)責(zé)執(zhí)行那些很耗時(shí)的后臺(tái)計(jì)算工作??梢哉{(diào)用 publishProgress方法來(lái)更新實(shí)時(shí)的任務(wù)進(jìn)度。該方法是抽象方法,子類(lèi)必須實(shí)現(xiàn)。 ,在publishProgress方法被調(diào)用后,UI thread將調(diào)用這個(gè)方法從而在界面上展示任務(wù)的進(jìn)展情況,例如通過(guò)一個(gè)進(jìn)度條進(jìn)行展示。 ,在doInBackground 執(zhí)行完成后,onPostExecute 方法將被UI thread調(diào)用,后臺(tái)的計(jì)算結(jié)果將通過(guò)該方法傳遞到UI thread. 為了正確的使用AsyncTask類(lèi),以下是幾條必須遵守的準(zhǔn)則: 1) Task的實(shí)例必須在UI thread中創(chuàng)建 2) execute方法必須在UI thread中調(diào)用 3) 不要手動(dòng)的調(diào)用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)這幾個(gè)方法 4) 該task只能被執(zhí)行一次,否則多次調(diào)用時(shí)將會(huì)出現(xiàn)異常</div |