Android多线程----异步消息处理机制之Handler
生活随笔
收集整理的這篇文章主要介紹了
Android多线程----异步消息处理机制之Handler
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
雖然是國慶佳節(jié),但也不能停止學習的腳步,我選擇在教研室為祖國母親默默地慶生。
關于Android的多線程知識,請參考本人之前的一篇博客:Android 多線程----AsyncTask異步任務詳解
在Android當中,提供了異步消息處理機制的兩種方式來解決線程之間的通信問題,一種是今天要講的Handler的機制,還有一種就是之前講過的 AsyncTask 機制。
一、handler的引入:
我們都知道,Android UI是線程不安全的,如果在子線程中嘗試進行UI操作,程序就有可能會崩潰。相信大家在日常的工作當中都會經(jīng)常遇到這個問題,解決的方案應該也是早已爛熟于心,即創(chuàng)建一個Message對象,然后借助Handler發(fā)送出去,之后在Handler的handleMessage()方法中獲得剛才發(fā)送的Message對象,然后在這里進行UI操作就不會再出現(xiàn)崩潰了。具體實現(xiàn)代碼如下:
復制代碼
1 package com.example.androidthreadtest;
2?
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.os.Handler;
6 import android.os.Message;
7 import android.view.View;
8 import android.view.View.OnClickListener;
9 import android.widget.Button;
10 import android.widget.TextView;
11?
12 public class MainActivity extends Activity implements OnClickListener {
13?
14 ? ? public static final int UPDATE_TEXT = 1;
15 ? ? private TextView text;
16 ? ? private Button changeText;
17 ? ? private Handler handler = new Handler() {
18 ? ? ? ? public void handleMessage(Message msg) {
19 ? ? ? ? ? ? switch (msg.what) {
20 ? ? ? ? ? ? case UPDATE_TEXT:
21 ? ? ? ? ? ? ? ? text.setText("Nice to meet you");
22 ? ? ? ? ? ? ? ? break;
23 ? ? ? ? ? ? default:
24 ? ? ? ? ? ? ? ? break;
25 ? ? ? ? ? ? }
26 ? ? ? ? }
27 ? ? };
28?
29 ? ? @Override
30 ? ? protected void onCreate(Bundle savedInstanceState) {
31 ? ? ? ? super.onCreate(savedInstanceState);
32 ? ? ? ? setContentView(R.layout.activity_main);
33 ? ? ? ? text = (TextView) findViewById(R.id.text);
34 ? ? ? ? changeText = (Button) findViewById(R.id.change_text);
35 ? ? ? ? changeText.setOnClickListener(this);
36 ? ? }
37?
38 ? ? @Override
39 ? ? public void onClick(View v) {
40 ? ? ? ? switch (v.getId()) {
41 ? ? ? ? case R.id.change_text:
42 ? ? ? ? ? ? new Thread(new Runnable() {
43 ? ? ? ? ? ? ? ? @Override
44 ? ? ? ? ? ? ? ? public void run() {
45 ? ? ? ? ? ? ? ? ? ? Message message = new Message();
46 ? ? ? ? ? ? ? ? ? ? message.what = UPDATE_TEXT;
47 ? ? ? ? ? ? ? ? ? ? handler.sendMessage(message);
48 ? ? ? ? ? ? ? ? }
49 ? ? ? ? ? ? }).start();
50 ? ? ? ? ? ? break;
51 ? ? ? ? default:
52 ? ? ? ? ? ? break;
53 ? ? ? ? }
54 ? ? }
55 }
復制代碼
上方第45行代碼也可以換成:
Message msg = handler.obtainMessage();?
上面的代碼中,我們并沒有在子線程中直接進行UI操作,而是創(chuàng)建了一個Message對象,并將它的what字段的值指定為了一個整形常量UPDATE_TEXT,用于表示更新TextView這個動作。然后調(diào)用Handler的sendMessage()方法將這條Message發(fā)送出去。很快,Handler就會收到這條Message,并在handleMessage()方法,在這里對具體的Message進行處理(需要注意的是,此時handleMessage()方法中的代碼是在主線程中運行的)。如果發(fā)現(xiàn)Message的what字段的值等于UPDATE_TEXT,就將TextView顯示的內(nèi)容更新。運行程序后,點擊按鈕,TextView就會顯示出更新的內(nèi)容。
二、異步消息處理機制:
Handler是Android類庫提供的用于接受、傳遞和處理消息或Runnable對象的處理類,它結合Message、MessageQueue和Looper類以及當前線程實現(xiàn)了一個消息循環(huán)機制,用于實現(xiàn)任務的異步加載和處理。整個異步消息處理流程的示意圖如下圖所示:
根據(jù)上面的圖片,我們現(xiàn)在來解析一下異步消息處理機制:
Message:消息體,用于裝載需要發(fā)送的對象。
handler:它直接繼承自Object。作用是:在子線程中發(fā)送Message或者Runnable對象到MessageQueue中;在UI線程中接收、處理從MessageQueue分發(fā)出來的Message或者Runnable對象。發(fā)送消息一般使用Handler的sendMessage()方法,而發(fā)出去的消息經(jīng)過處理后最終會傳遞到Handler的handlerMessage()方法中。
MessageQueue:用于存放Message或Runnable對象的消息隊列。它由對應的Looper對象創(chuàng)建,并由Looper對象管理。每個線程中都只會有一個MessageQueue對象。
Looper:是每個線程中的MessageQueue的管家,循環(huán)不斷地管理MessageQueue接收和分發(fā)Message或Runnable的工作。調(diào)用Looper的loop()方法后,就會進入到一個無限循環(huán)中然后每當發(fā)現(xiàn)MessageQueue中存在一條消息,就會將它取出,并調(diào)用Handler的handlerMessage()方法。每個線程中也只會有一個Looper對象。
了解這些之后,我們在來看一下他們之間的聯(lián)系:
首先要明白的是,Handler和Looper對象是屬于線程內(nèi)部的數(shù)據(jù),不過也提供與外部線程的訪問接口,Handler就是公開給外部線程的接口,用于線程間的通信。Looper是由系統(tǒng)支持的用于創(chuàng)建和管理MessageQueue的依附于一個線程的循環(huán)處理對象,而Handler是用于操作線程內(nèi)部的消息隊列的,所以Handler也必須依附一個線程,而且只能是一個線程。
我們再來對異步消息處理的整個流程梳理一遍:
當應用程序開啟時,系統(tǒng)會自動為UI線程創(chuàng)建一個MessageQueue(消息隊列)和Looper循環(huán)處理對象。首先需要在主線程中創(chuàng)建一個Handler對象,并重寫handlerMessage()方法。然后當子線程中需要進行UI操作時,就創(chuàng)建一個Message對象,并通過Handler將這條消息發(fā)送出去。之后這條消息就會被添加到MessageQueue的隊列中等待被處理,而Looper則會一直嘗試從MessageQueue中取出待處理消息,并找到與消息對象對應的Handler對象,然后調(diào)用Handler的handleMessage()方法。由于Handler是在主線程中創(chuàng)建的,所以此時handleMessage()方法中的代碼也會在主線程中運行,于是我們在這里就可以安心地進行UI操作了。
通俗地來講,一般我們在實際的開發(fā)過程中用的比較多一種情況的就是主線程的Handler將子線程中處理過的耗時操作的結果封裝成Message(消息),并將該Message(利用主線程里的MessageQueue和Looper)傳遞到主線程中,最后主線程再根據(jù)傳遞過來的結果進行相關的UI元素的更新,從而實現(xiàn)任務的異步加載和處理,并達到線程間的通信。
通過上一小節(jié)對Handler的一個初步認識后,我們可以很容易總結出Handler的主要用途,下面是Android官網(wǎng)總結的關于Handler類的兩個主要用途:
(1)線程間的通信:
在執(zhí)行較為耗時的操作時,Handler負責將子線程中執(zhí)行的操作的結果傳遞到UI線程,然后UI線程再根據(jù)傳遞過來的結果進行相關UI元素的更新。(上面已有說明)
(2)執(zhí)行定時任務:
指定任務時間,在某個具體時間或某個時間段后執(zhí)行特定的任務操作,例如使用Handler提供的postDelayed(Runnable r,long delayMillis)方法指定在多久后執(zhí)行某項操作,比如當當、淘寶、京東和微信等手機客戶端的開啟界面功能,都是通過Handler定時任務來完成的。
我們接下來講一下post。
三、post:
對于Handler的Post方式來說,它會傳遞一個Runnable對象到消息隊列中,在這個Runnable對象中,重寫run()方法。一般在這個run()方法中寫入需要在UI線程上的操作。
Post允許把一個Runnable對象入隊到消息隊列中。它的方法有:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。詳細解釋如下:
boolean post(Runnable r):把一個Runnable入隊到消息隊列中,UI線程從消息隊列中取出這個對象后,立即執(zhí)行。
boolean postAtTime(Runnable r,long uptimeMillis):把一個Runnable入隊到消息隊列中,UI線程從消息隊列中取出這個對象后,在特定的時間執(zhí)行。
boolean postDelayed(Runnable r,long delayMillis):把一個Runnable入隊到消息隊列中,UI線程從消息隊列中取出這個對象后,延遲delayMills秒執(zhí)行
void removeCallbacks(Runnable r):從消息隊列中移除一個Runnable對象。
下面通過一個Demo,講解如何通過Handler的post方式在新啟動的線程中修改UI組件的屬性:
復制代碼
1 package com.example.m03_threadtest01;
2?
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.os.Handler;
6 import android.view.View;
7 import android.widget.Button;
8 import android.widget.TextView;
9?
10 public class MainActivity extends Activity {
11 ? ? private Button btnMes1,btnMes2;
12 ? ? private TextView tvMessage;
13 ? ? // 聲明一個Handler對象
14 ? ? private static Handler handler=new Handler();
15 ? ??
16 ? ? @Override
17 ? ? protected void onCreate(Bundle savedInstanceState) {
18 ? ? ? ? super.onCreate(savedInstanceState);
19 ? ? ? ? setContentView(R.layout.activity_main); ? ? ? ?
20 ? ? ? ??
21 ? ? ? ? btnMes1=(Button)findViewById(R.id.button1);
22 ? ? ? ? btnMes2=(Button)findViewById(R.id.button2);
23 ? ? ? ? tvMessage=(TextView)findViewById(R.id.TextView1);
24 ? ? ? ? btnMes1.setOnClickListener(new View.OnClickListener() {
25 ? ? ? ? ? ??
26 ? ? ? ? ? ? @Override
27 ? ? ? ? ? ? public void onClick(View v) {
28 ? ? ? ? ? ? ? ? // 新啟動一個子線程
29 ? ? ? ? ? ? ? ? new Thread(new Runnable() { ? ? ? ? ? ? ? ? ? ?
30 ? ? ? ? ? ? ? ? ? ? @Override
31 ? ? ? ? ? ? ? ? ? ? public void run() {
32 ? ? ? ? ? ? ? ? ? ? ? ? // tvMessage.setText("...");
33 ? ? ? ? ? ? ? ? ? ? ? ? // 以上操作會報錯,無法再子線程中訪問UI組件,UI組件的屬性必須在UI線程中訪問
34 ? ? ? ? ? ? ? ? ? ? ? ? // 使用post方式修改UI組件tvMessage的Text屬性
35 ? ? ? ? ? ? ? ? ? ? ? ? handler.post(new Runnable() { ? ? ? ? ? ? ? ? ? ?
36 ? ? ? ? ? ? ? ? ? ? ? ? ? ? @Override
37 ? ? ? ? ? ? ? ? ? ? ? ? ? ? public void run() {
38 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? tvMessage.setText("使用Handler.post在工作線程中發(fā)送一段執(zhí)行到消息隊列中,在主線程中執(zhí)行。"); ? ? ? ? ? ? ? ? ? ? ? ?
39 ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
40 ? ? ? ? ? ? ? ? ? ? ? ? }); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
41 ? ? ? ? ? ? ? ? ? ? }
42 ? ? ? ? ? ? ? ? }).start();
43 ? ? ? ? ? ? }
44 ? ? ? ? });
45 ? ? ? ??
46 ? ? ? ? btnMes2.setOnClickListener(new View.OnClickListener() {
47 ? ? ? ? ? ??
48 ? ? ? ? ? ? @Override
49 ? ? ? ? ? ? public void onClick(View v) {
50 ? ? ? ? ? ? ? ? new Thread(new Runnable() { ? ? ? ? ? ? ? ? ? ?
51 ? ? ? ? ? ? ? ? ? ? @Override
52 ? ? ? ? ? ? ? ? ? ? public void run() {
53 ? ? ? ? ? ? ? ? ? ? ? ? // 使用postDelayed方式修改UI組件tvMessage的Text屬性值
54 ? ? ? ? ? ? ? ? ? ? ? ? // 并且延遲3S執(zhí)行
55 ? ? ? ? ? ? ? ? ? ? ? ? handler.postDelayed(new Runnable() {
56 ? ? ? ? ? ? ? ? ? ? ? ? ? ??
57 ? ? ? ? ? ? ? ? ? ? ? ? ? ? @Override
58 ? ? ? ? ? ? ? ? ? ? ? ? ? ? public void run() {
59 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? tvMessage.setText("使用Handler.postDelayed在工作線程中發(fā)送一段執(zhí)行到消息隊列中,在主線程中延遲3S執(zhí)行。"); ? ?
60 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
61 ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
62 ? ? ? ? ? ? ? ? ? ? ? ? }, 3000); ? ? ? ? ? ? ? ? ? ? ? ?
63 ? ? ? ? ? ? ? ? ? ? }
64 ? ? ? ? ? ? ? ? }).start();
65 ? ? ? ? ? ? ? ??
66 ? ? ? ? ? ? }
67 ? ? ? ? });
68 ? ? }
69 ? ??
70 }
復制代碼
點擊按鈕,運行結果如下:
有一點值得注意的是,對于Post方式而言,它其中Runnable對象的run()方法的代碼,均執(zhí)行在UI線程上(雖然是寫在子線程當中的),所以對于這段代碼而言,不能執(zhí)行在UI線程上的操作,一樣無法使用post方式執(zhí)行,比如說訪問網(wǎng)絡。?
四、Message:
Handler如果使用sendMessage的方式把消息入隊到消息隊列中,需要傳遞一個Message對象,而在Handler中,需要重寫handleMessage()方法,用于獲取工作線程傳遞過來的消息,此方法運行在UI線程上。
對于Message對象,一般并不推薦直接使用它的構造方法得到,而是建議通過使用Message.obtain()這個靜態(tài)的方法或者Handler.obtainMessage()獲取。Message.obtain()會從消息池中獲取一個Message對象,如果消息池中是空的,才會使用構造方法實例化一個新Message,這樣有利于消息資源的利用。并不需要擔心消息池中的消息過多,它是有上限的,上限為10個。Handler.obtainMessage()具有多個重載方法,如果查看源碼,會發(fā)現(xiàn)其實Handler.obtainMessage()在內(nèi)部也是調(diào)用的Message.obtain()。
Handler中,與Message發(fā)送消息相關的方法有:
Message obtainMessage():獲取一個Message對象。
boolean sendMessage():發(fā)送一個Message對象到消息隊列中,并在UI線程取到消息后,立即執(zhí)行。
boolean sendMessageDelayed():發(fā)送一個Message對象到消息隊列中,在UI線程取到消息后,延遲執(zhí)行。
boolean sendEmptyMessage(int what):發(fā)送一個空的Message對象到隊列中,并在UI線程取到消息后,立即執(zhí)行。
boolean sendEmptyMessageDelayed(int what,long delayMillis):發(fā)送一個空Message對象到消息隊列中,在UI線程取到消息后,延遲執(zhí)行。
void removeMessage():從消息隊列中移除一個未響應的消息。
五、通過Handler實現(xiàn)線程間通信:
1、在Worker Thread發(fā)送消息,在MainThread中接收消息:
【實例】點擊反扭,將下方的TextView的內(nèi)容修改為“從網(wǎng)絡中獲取的數(shù)據(jù)”
【實際意義】點擊按鈕時,程序訪問服務器,服務器接到請求之后,會返回字符串結果,然后更新到程序。
完整版代碼如下:
XML布局文件代碼如下:
復制代碼
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/TextViewId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="數(shù)據(jù)" /> ??
<Button
android:id="@+id/ButtonId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="發(fā)送消息"?
android:layout_below="@id/TextViewId"/>
</RelativeLayout>?
復制代碼
MainActivity.java代碼如下:
復制代碼
1 package com.example.test0207_handler;
2?
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.os.Handler;
6 import android.os.Message;
7 import android.view.Menu;
8 import android.view.View;
9 import android.view.View.OnClickListener;
10 import android.widget.Button;
11 import android.widget.TextView;
12?
13 public class MainActivity extends Activity {
14?
15 ? ? private TextView textView ;?
16 ? ? private Button button ;
17 ? ? private Handler handler ;
18 ? ? @Override
19 ? ? protected void onCreate(Bundle savedInstanceState) {
20 ? ? ? ? super.onCreate(savedInstanceState);
21 ? ? ? ? setContentView(R.layout.activity_main);
22 ? ? ? ??
23 ? ? ? ? textView = (TextView)findViewById(R.id.TextViewId) ;
24 ? ? ? ? button = (Button)findViewById(R.id.ButtonId) ; ? ?
25 ? ? ? ??
26 ? ? ? ? handler = new MyHandler() ;
27 ? ? ? ??
28 ? ? ? ? button.setOnClickListener(new ButtonListener()) ;
29 ? ? ? ??
30 ? ? }
31 ? ? //在MainAthread線程中接收數(shù)據(jù),從而修改TextView的值
32 ? ? class MyHandler extends Handler {
33 ? ? ? ? @Override
34 ? ? ? ? public void handleMessage(Message msg) {
35 ? ? ? ? ? ? System.out.println("handleMessage--->"+Thread.currentThread().getName()) ;//得到當前線程的名字
36 ? ? ? ? ? ? String s = (String)msg.obj ;
37 ? ? ? ? ? ? textView.setText(s) ;
38 ? ? ? ? }
39 ? ? ? ??
40 ? ? }
41 ? ? //生成線程對象,讓NetworkThread線程啟動
42 ? ? class ButtonListener implements OnClickListener {
43 ? ? ? ? @Override ? ? ? ?
44 ? ? ? ? public void onClick(View arg0) {
45 ? ? ? ? ? ? Thread t = new NetworkThread() ;
46 ? ? ? ? ? ? t.start();
47 ? ? ? ? }
48 ? ? ? ??
49 ? ? }
50 ? ??
51 ? ? //在Worker Thread線程中發(fā)送數(shù)據(jù)
52 ? ? class NetworkThread extends Thread {
53 ? ? ? ? @Override?
54 ? ? ? ? public void run(){
55 ? ? ? ? ? ??
56 ? ? ? ? ? ? System.out.println("network--->"+Thread.currentThread().getName()) ;//得到當前線程的名字
57 ? ? ? ? ? ??
58 ? ? ? ? ? ? //模擬訪問網(wǎng)絡:當線程運行時,首先休眠2秒鐘
59 ? ? ? ? ? ? try {
60 ? ? ? ? ? ? ? ? Thread.sleep(2*1000) ;
61 ? ? ? ? ? ? } catch (InterruptedException e) {
62 ? ? ? ? ? ? ? ? e.printStackTrace();
63 ? ? ? ? ? ? }
64 ? ? ? ? ? ? //變量s的值,模擬從網(wǎng)絡當中獲取的數(shù)據(jù)
65 ? ? ? ? ? ? String s = "從網(wǎng)絡中獲取的數(shù)據(jù)" ;
66 ? ? ? ? ? ? //textView.setText(s) ; //這種做法是錯誤的,只有在Mainthread中才能操作UI ? ? ? ? ? ?
67 ? ? ? ? ? ??
68 ? ? ? ? ? ? //開始發(fā)送消息
69 ? ? ? ? ? ? Message msg = handler.obtainMessage() ; ? ?
70 ? ? ? ? ? ? msg.obj = s ;
71 ? ? ? ? ? ? handler.sendMessage(msg) ;//sendMessage()方法,在主線程或者Worker Thread線程中發(fā)送,都是可以的,都可以被取到
72 ? ? ? ? }
73 ? ? } ? ?
74 ? ??
75 ? ? @Override
76 ? ? public boolean onCreateOptionsMenu(Menu menu) {
77 ? ? ? ? // Inflate the menu; this adds items to the action bar if it is present.
78 ? ? ? ? getMenuInflater().inflate(R.menu.main, menu);
79 ? ? ? ? return true;
80 ? ? }
81 ? ??
82 }
復制代碼
這段代碼的結構,和最上面的第一章節(jié)是一樣的。
上方代碼中,我們在子線程中休眠2秒來模擬訪問網(wǎng)絡的操作。
65行:用字符串s表示從網(wǎng)絡中獲取的數(shù)據(jù);70行:然后我們把這個字符串放在Message的obj屬性當中發(fā)送出去,并在主線程中接收(36行)。
運行后結果如下:
點擊按鈕后結果如下:
點擊按鈕后,后臺輸出結果如下:
可以看到,子線程的名字是:Thread-1118,主線程的名字是:main。
2、在MainThread中發(fā)送消息,在Worker Thread中接收消息:
【實例】點擊按鈕,在在MainThread中發(fā)送消息,在Worker Thread中接收消息,并在后臺打印輸出。
【代碼】完整版代碼如下:
XML布局文件代碼如下:
復制代碼
<RelativeLayout?
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:id="@+id/ButtonId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="在主線程中發(fā)送消息" />
</RelativeLayout>?
復制代碼
MainActivity.java代碼如下:
復制代碼
1 package com.example.m03_handle01;
2?
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.os.Handler;
6 import android.os.Looper;
7 import android.os.Message;
8 import android.util.Log;
9 import android.view.Menu;
10 import android.view.View;
11 import android.view.View.OnClickListener;
12 import android.widget.Button;
13 public class MainActivity extends Activity {
14 ? ? private Button button ;
15 ? ? private Handler handler ;
16 ? ? @Override
17 ? ? protected void onCreate(Bundle savedInstanceState) {
18 ? ? ? ? super.onCreate(savedInstanceState);
19 ? ? ? ? setContentView(R.layout.activity_main);
20 ? ? ? ??
21 ? ? ? ? button = (Button)findViewById(R.id.ButtonId) ;
22 ? ? ? ??
23 ? ? ? ? //當用戶點擊按鈕時,發(fā)送Message的對象msg
24 ? ? ? ? button.setOnClickListener(new OnClickListener() { ?//使用匿名內(nèi)部類為button綁定監(jiān)聽器
25 ? ? ? ? ? ??
26 ? ? ? ? ? ? @Override
27 ? ? ? ? ? ? public void onClick(View v) {
28 ? ? ? ? ? ? ? ? Log.i("onClick:", Thread.currentThread().getName());
29 ? ? ? ? ? ? ? ? Message msg = handler.obtainMessage() ;
30 ? ? ? ? ? ? ? ? handler.sendMessage(msg) ;
31 ? ? ? ? ? ? } ? ? ? ? ? ?
32 ? ? ? ? }) ;
33 ? ? ? ??
34 ? ? ? ? WorkerThread wt = new WorkerThread() ;
35 ? ? ? ? wt.start() ;
36 ? ? }
37?
38 ? ? //在WorkerThread生成handler
39 ? ? class WorkerThread extends ?Thread {
40 ? ? ? ? @Override
41 ? ? ? ? public void run() {
42 ? ? ? ? ? ? //準備Looper對象
43 ? ? ? ? ? ? Looper.prepare() ;
44 ? ? ? ? ? ? //在WorkerThread當中生成一個Handler對象
45 ? ? ? ? ? ? handler = new Handler() {
46 ? ? ? ? ? ? ? ? @Override
47 ? ? ? ? ? ? ? ? public void handleMessage(Message msg) {
48 ? ? ? ? ? ? ? ? ? ? Log.i("handleMessage:", Thread.currentThread().getName());
49 ? ? ? ? ? ? ? ? ? ? Log.i("后臺輸出", "收到了消息對象");
50 ? ? ? ? ? ? ? ? }
51 ? ? ? ? ? ? };
52 ? ? ? ? ? ? //調(diào)用Looper的loop()方法之后,Looper對象將不斷地從消息隊列當中取出對象,然后調(diào)用handler的handleMessage()方法,處理該消息對象
53 ? ? ? ? ? ? //如果消息隊列中沒有對象,則該線程阻塞
54 ? ? ? ? ? ? Looper.loop() ; ? //通過Looper對象將消息取出來
55 ? ? ? ? }
56 ? ? ? ??
57 ? ? }
58 ? ??
59 ? ??
60 ? ? @Override
61 ? ? public boolean onCreateOptionsMenu(Menu menu) {
62 ? ? ? ? // Inflate the menu; this adds items to the action bar if it is present.
63 ? ? ? ? getMenuInflater().inflate(R.menu.main, menu);
64 ? ? ? ? return true;
65 ? ? }
66 ? ??
67 }?
復制代碼
上方的第42行至54行代碼:這是MainThread中發(fā)送消息,在Worker Thread中接收消息的固定寫法。上面的三個步驟再重復一下:
準備Looper對象
在WorkerThread當中生成一個Handler對象
調(diào)用Looper的loop()方法之后,Looper對象將不斷地從消息隊列當中取出對象,然后調(diào)用handler的handleMessage()方法,處理該消息對象;如果消息隊列中沒有對象,則該線程阻塞
注意,此時handleMessage()方法是在Worker Thread中運行的。
總結
以上是生活随笔為你收集整理的Android多线程----异步消息处理机制之Handler的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 中Message,Mes
- 下一篇: Looper、Handler应用---实