android多線程handler
❶ 關於Android Handler與Message的多線程消息的處理,為什我以下代碼會死掉 請高手看看,謝謝。
1.線程沒有終止條件,會一直給主線程發消息,主線程不停的調用handleMessage代碼,很容易ANR(應用程序不響應)
2.handler.obtainMessage()得到message對象比new Message();更高效
❷ Android線程之HandlerThread
HandlerThread是Thread的一個子類,是Android中提供的另一種線程形態。
我擦,有線程、有looper這不正是我們當初聲稱在子線程中構建handler消息系統的所需要的嗎?
那很明顯,這個 HandlerThread 的目的就是讓我們創建一個 Handler ,然後所有的任務操作成功的轉給了 Handler 來處理完成。
但注意的是這個 Handler 的消息處理是運行在子線程中的。
在主線程中創建 handler ,簡單的模擬一下 HandlerThread 工作原理
由於這個handler回調是運行在子線程中的,因此如果你想要更新UI可以藉助主線程的默認的looper來實現,這個問題又愉快的轉化到了子線程更新UI的問題。
HandlerThread其本質就是一個線程,只不過這個線程加入了Handler消息非同步處理的機制。
那這與普通的創建線程的好處是什麼呢?
❸ Android的handler機制的原理
Android的handler機制的原理分為非同步通信准備,消息發送,消息循環,消息處理。
1、非同步通信准備
在主線程中創建處理器對象(Looper)、消息隊列對象(Message Queue)和Handler對象。
2、消息入隊
工作線程通過Handler發送消息(Message) 到消息隊列(Message Queue)中。
3、消息循環
消息出隊: Looper循環取出消息隊列(Message Queue) 中的的消息(Message)。
消息分發: Looper將取出的消息 (Message) 發送給創建該消息的處理者(Handler)。
4、消息處理
處理者(Handler) 接收處理器(Looper) 發送過來的消息(Message),根據消息(Message) 進行U操作。
handler的作用
handler是android線程之間的消息機制,主要的作用是將一個任務切換到指定的線程中去執行,(准確的說是切換到構成handler的looper所在的線程中去出處理)android系統中的一個例子就是主線程中的所有操作都是通過主線程中的handler去處理的。
Handler的運行需要底層的 messagequeue和 looper做支撐。
❹ 深入分析Android-Handler消息機制
Handler是Android消息機制的上層介面。通過它可以輕松地將一個任務切換到Handler所在的線程中去執行。通常情況下,Handler的使用場景就是 更新UI 。
在子線程中,進行耗時操作,執行完操作後,發送消息,通知主線程更新UI。
Handler消息機制主要包括: MessageQueue 、 Handler 、 Looper 這三大部分,以及 Message 。
從上面的類圖可以看出:
MessageQueue、Handler和Looper三者之間的關系: 每個線程中只能存在一個Looper,Looper是保存在ThreadLocal中的。 主線程(UI線程)已經創建了一個Looper,所以在主線程中不需要再創建Looper,但是在其他線程中需要創建Looper。 每個線程中可以有多個Handler,即一個Looper可以處理來自多個Handler的消息。 Looper中維護一個MessageQueue,來維護消息隊列,消息隊列中的Message可以來自不同的Handler。
在子線程執行完耗時操作,當Handler發送消息時,將會調用 MessageQueue.enqueueMessage ,向消息隊列中添加消息。 當通過 Looper.loop 開啟循環後,會不斷地從消息池中讀取消息,即調用 MessageQueue.next , 然後調用目標Handler(即發送該消息的Handler)的 dispatchMessage 方法傳遞消息, 然後返回到Handler所在線程,目標Handler收到消息,調用 handleMessage 方法,接收消息,處理消息。
從上面可以看出,在子線程中創建Handler之前,要調用 Looper.prepare() 方法,Handler創建後,還要調用 Looper.loop() 方法。而前面我們在主線程創建Handler卻不要這兩個步驟,因為系統幫我們做了。
初始化Looper :
從上可以看出,不能重復創建Looper,每個線程只能創建一個。創建Looper,並保存在 ThreadLocal 。其中ThreadLocal是線程本地存儲區(Thread Local Storage,簡稱TLS),每個線程都有自己的私有的本地存儲區域,不同線程之間彼此不能訪問對方的TLS區域。
開啟Looper
創建Handler :
發送消息 :
post方法:
send方法:
❺ [Android源碼分析] - 非同步通信Handler機制
一、問題:在Android啟動後會在新進程里創建一個主線程,也叫UI線程( 非線程安全 )這個線程主要負責監聽屏幕點擊事件與界面繪制。當Application需要進行耗時操作如網路請求等,如直接在主線程進行容易發生ANR錯誤。所以會創建子線程來執行耗時任務,當子線程執行完畢需要通知UI線程並修改界面時,不可以直接在子線程修改UI,怎麼辦?
解決方法:Message Queue機制可以實現子線程與UI線程的通信。
該機制包括Handler、Message Queue、Looper。Handler可以把消息/ Runnable對象 發給Looper,由它把消息放入所屬線程的消息隊列中,然後Looper又會自動把消息隊列里的消息/Runnable對象 廣播 到所屬線程里的Handler,由Handler處理接收到的消息或Runnable對象。
1、Handler
每次創建Handler對象時,它會自動綁定到創建它的線程上。如果是主線程則默認包含一個Message Queue,否則需要自己創建一個消息隊列來存儲。
Handler是多個線程通信的信使。比如在線程A中創建AHandler,給它綁定一個ALooper,同時創建屬於A的消息隊列AMessageQueue。然後在線程B中使用AHandler發送消息給ALooper,ALooper會把消息存入到AMessageQueue,然後再把AMessageQueue廣播給A線程里的AHandler,它接收到消息會進行處理。從而實現通信。
2、Message Queue
在主線程里默認包含了一個消息隊列不需要手動創建。在子線程里,使用Looper.prepare()方法後,會先檢查子線程是否已有一個looper對象,如果有則無法創建,因為每個線程只能擁有一個消息隊列。沒有的話就為子線程創建一個消息隊列。
Handler類包含Looper指針和MessageQueue指針,而Looper里包含實際MessageQueue與當前線程指針。
下面分別就UI線程和worker線程講解handler創建過程:
首先,創建handler時,會自動檢查當前線程是否包含looper對象,如果包含,則將handler內的消息隊列指向looper內部的消息隊列,否則,拋出異常請求執行looper.prepare()方法。
- 在 UI線程 中,系統自動創建了Looper 對象,所以,直接new一個handler即可使用該機制;
- 在 worker線程 中,如果直接創建handler會拋出運行時異常-即通過查『線程-value』映射表發現當前線程無looper對象。所以需要先調用Looper.prepare()方法。在prepare方法里,利用ThreadLocal<Looper>對象為當前線程創建一個Looper(利用了一個Values類,即一個Map映射表,專為thread存儲value,此處為當前thread存儲一個looper對象)。然後繼續創建handler, 讓handler內部的消息隊列指向該looper的消息隊列(這個很重要,讓handler指向looper里的消息隊列,即二者共享同一個消息隊列,然後handler向這個消息隊列發送消息,looper從這個消息隊列獲取消息) 。然後looper循環消息隊列即可。當獲取到message消息,會找出message對象里的target,即原始發送handler,從而回調handler的handleMessage() 方法進行處理。
- handler與looper共享消息隊列 ,所以handler發送消息只要入列,looper直接取消息即可。
- 線程與looper映射表 :一個線程最多可以映射一個looper對象。通過查表可知當前線程是否包含looper,如果已經包含則不再創建新looper。
5、基於這樣的機制是怎樣實現線程隔離的,即在線程中通信呢。
核心在於 每一個線程擁有自己的handler、message queue、looper體系 。而 每個線程的Handler是公開 的。B線程可以調用A線程的handler發送消息到A的共享消息隊列去,然後A的looper會自動從共享消息隊列取出消息進行處理。反之一樣。
二、上面是基於子線程中利用主線程提供的Handler發送消息出去,然後主線程的Looper從消息隊列中獲取並處理。那麼還有另外兩種情況:
1、主線程發送消息到子線程中;
採用的方法和前面類似。要在子線程中實例化AHandler並設定處理消息的方法,同時由於子線程沒有消息隊列和Looper的輪詢,所以要加上Looper.prepare(),Looper.loop()分別創建消息隊列和開啟輪詢。然後在主線程中使用該AHandler去發送消息即可。
2、子線程A與子線程B之間的通信。
1、 Handler為什麼能夠實現不同線程的通信?核心點在哪?
不同線程之間,每個線程擁有自己的Handler、消息隊列和Looper。Handler是公共的,線程可以通過使用目標線程的Handler對象來發送消息,這個消息會自動發送到所屬線程的消息隊列中去,線程自帶的Looper對象會不斷循環從裡面取出消息並把消息發送給Handler,回調自身Handler的handlerMessage方法,從而實現了消息的線程間傳遞。
2、 Handler的核心是一種事件激活式(類似傳遞一個中斷)的還是主要是用於傳遞大量數據的?重點在Message的內容,偏向於數據傳輸還是事件傳輸。
目前的理解,它所依賴的是消息隊列,發送的自然是消息,即類似事件中斷。
0、 Android消息處理機制(Handler、Looper、MessageQueue與Message)
1、 Handler、Looper源碼閱讀
2、 Android非同步消息處理機制完全解析,帶你從源碼的角度徹底理解
謝謝!
wingjay

❻ Android進程間和線程間通信方式
進程:是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。
線程:是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。線程自己基本上不擁有系統資源,只擁有一些在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。
區別:
(1)、一個程序至少有一個進程,一個進程至少有一個線程;
(2)、線程的劃分尺度小於進程,使得多線程程序的並發性高;
(3)、進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,但線程之間沒有單獨的地址空間,一個線程死掉就等於整個進程死掉。
---------------------
一、Android進程間通信方式
1.Bundle
由於Activity,Service,Receiver都是可以通過Intent來攜帶Bundle傳輸數據的,所以我們可以在一個進程中通過Intent將攜帶數據的Bundle發送到另一個進程的組件。
缺點:無法傳輸Bundle不支持的數據類型。
2.ContentProvider
ContentProvider是Android四大組件之一,以表格的方式來儲存數據,提供給外界,即Content Provider可以跨進程訪問其他應用程序中的數據。用法是繼承ContentProvider,實現onCreate,query,update,insert,delete和getType方法,onCreate是負責創建時做一些初始化的工作,增刪查改的方法就是對數據的查詢和修改,getType是返回一個String,表示Uri請求的類型。注冊完後就可以使用ContentResolver去請求指定的Uri。
3.文件
兩個進程可以到同一個文件去交換數據,我們不僅可以保存文本文件,還可以將對象持久化到文件,從另一個文件恢復。要注意的是,當並發讀/寫時可能會出現並發的問題。
4.Broadcast
Broadcast可以向android系統中所有應用程序發送廣播,而需要跨進程通訊的應用程序可以監聽這些廣播。
5.AIDL方式
Service和Content Provider類似,也可以訪問其他應用程序中的數據,Content Provider返回的是Cursor對象,而Service返回的是Java對象,這種可以跨進程通訊的服務叫AIDL服務。
AIDL通過定義服務端暴露的介面,以提供給客戶端來調用,AIDL使伺服器可以並行處理,而Messenger封裝了AIDL之後只能串列運行,所以Messenger一般用作消息傳遞。
6.Messenger
Messenger是基於AIDL實現的,服務端(被動方)提供一個Service來處理客戶端(主動方)連接,維護一個Handler來創建Messenger,在onBind時返回Messenger的binder。
雙方用Messenger來發送數據,用Handler來處理數據。Messenger處理數據依靠Handler,所以是串列的,也就是說,Handler接到多個message時,就要排隊依次處理。
7.Socket
Socket方法是通過網路來進行數據交換,注意的是要在子線程請求,不然會堵塞主線程。客戶端和服務端建立連接之後即可不斷傳輸數據,比較適合實時的數據傳輸
二、Android線程間通信方式
一般說線程間通信主要是指主線程(也叫UI線程)和子線程之間的通信,主要有以下兩種方式:
1.AsyncTask機制
AsyncTask,非同步任務,也就是說在UI線程運行的時候,可以在後台的執行一些非同步的操作;AsyncTask可以很容易且正確地使用UI線程,AsyncTask允許進行後台操作,並在不顯示使用工作線程或Handler機制的情況下,將結果反饋給UI線程。但是AsyncTask只能用於短時間的操作(最多幾秒就應該結束的操作),如果需要長時間運行在後台,就不適合使用AsyncTask了,只能去使用Java提供的其他API來實現。
2.Handler機制
Handler,繼承自Object類,用來發送和處理Message對象或Runnable對象;Handler在創建時會與當前所在的線程的Looper對象相關聯(如果當前線程的Looper為空或不存在,則會拋出異常,此時需要在線程中主動調用Looper.prepare()來創建一個Looper對象)。使用Handler的主要作用就是在後面的過程中發送和處理Message對象和讓其他的線程完成某一個動作(如在工作線程中通過Handler對象發送一個Message對象,讓UI線程進行UI的更新,然後UI線程就會在MessageQueue中得到這個Message對象(取出Message對象是由其相關聯的Looper對象完成的),並作出相應的響應)。
三、Android兩個子線程之間通信
面試的過程中,有些面試官可能會問Android子線程之間的通信方式,由於絕大部分程序員主要關注的是Android主線程和子線程之間的通信,所以這個問題很容易讓人懵逼。
主線程和子線程之間的通信可以通過主線程中的handler把子線程中的message發給主線程中的looper,或者,主線程中的handler通過post向looper中發送一個runnable。但looper默認存在於main線程中,子線程中沒有Looper,該怎麼辦呢?其實原理很簡單,把looper綁定到子線程中,並且創建一個handler。在另一個線程中通過這個handler發送消息,就可以實現子線程之間的通信了。
子線程創建handler的兩種方式:
方式一:給子線程創建Looper對象:
new Thread(new Runnable() {
public void run() {
Looper.prepare(); // 給這個Thread創建Looper對象,一個Thead只有一個Looper對象
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
Looper.loop(); // 不斷遍歷MessageQueue中是否有消息
};
}).start();
---------------------
方式二:獲取主線程的looper,或者說是UI線程的looper:
new Thread(new Runnable() {
public void run() {
Handler handler = new Handler(Looper.getMainLooper()){ // 區別在這!!!
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
};
}).start();
---------------------
❼ Android面試 Handler機制
Handler就是解決線程與線程間的通信。
當我們在子線程處理耗時操作,耗時操作完成後我們需要更新UI的時候,這就是需要使用Handler來處理了,因為子線程不能更 新UI,Handler能讓我們容易的把任務切換回來它所在的線程。
消息處理機制本質:一個線程開啟循環模式持續監聽並依次處理其他線程給它發的消息。
一個線程可以有多個Handler,通過new Handler的方式創建。
一個線程只能有一個Looper,通過Looper.perpare方法會創建一個Looper保存在ThreadLocal中,每個線程都有一個LocalThreadMap,會將Looper保存在對應線程中的LocalThreadMap,key為ThreadLocal,value為Looper。
內部類持有外部類的對象,handler持有activity的對象,當頁面activity關閉時,handler還在發送消息,handler持有activity的對象,導致handler不能及時被回收,所以造成內存泄漏。
因為當handler發送消息時,會有耗時操作,並且會利用線程中的looper和messageQueue進行消息發送,looper和messageQueue的生命周期是很長的,和application一樣,所以handler不容易被銷毀,所以造成內存泄漏。
解決方案有:
可以在子線程中創建Handler,我們需要調用Looper.perpare和Looper.loop方法。或者通過獲取主線程的looper來創建Handler。
應該調用Looper的quit方法,因為可以將looper中的messageQueue里的message都移除掉,並且將內存釋放。
通過synchronized鎖機制保證線程安全。
Message.obtain來創建Message。這樣會復用之前的Message的內存,不會頻繁的創建對象,導致內存抖動。
點擊按鈕的時候會發送消息到Handler,但是為了保證優先執行,會加一個標記非同步,同時會發送一個target為null的消息,這樣在使用消息隊列的next獲取消息的時候,如果發現消息的target為null,那麼會遍歷消息隊列將有非同步標記的消息獲取出來優先執行,執行完之後會將target為null的消息移除。(同步屏障)
更多內容戳這里(整理好的各種文集)
❽ android 多線程編程,用runnable和handler
本來開辟一個新的線程是屬於子線程,但是你的Handler是跟主線程綁定的。嚴格來說是在子線程中運行。
❾ Android多線程的四種方式:Handler、AsyncTask、ThreadPoolExector、IntentService
非同步通信機制,將工作線程中需更新UI的操作信息 傳遞到 UI主線程,從而實現 工作線程對UI的更新處理,最終實現非同步消息的處理。Handler不僅僅能將子線程的數據傳遞給主線程,它能實現任意兩個線程的數據傳遞。
(1)Message
Message 可以在線程之間傳遞消息。可以在它的內部攜帶少量數據,用於在不同線程之間進行數據交換。除了 what 欄位,還可以使用 arg1 和 arg2 來攜帶整型數據,使用 obj 來攜帶 Object 數據。
(2) Handler
Handler 作為處理中心,用於發送(sendMessage 系列方法)與處理消息(handleMessage 方法)。
(3) MessageQueue
MessageQueue 用於存放所有通過 Handler 發送的消息。這部分消息會一直存放在消息隊列中,直到被處理。每個線程中只會有一個 MessageQueue 對象
(4) Looper
Looper 用於管理 MessageQueue 隊列,Looper對象通過loop()方法開啟了一個死循環——for (;;){},不斷地從looper內的MessageQueue中取出Message,並傳遞到 Handler 的 handleMessage() 方法中。每個線程中只會有一個 Looper 對象。
AsyncTask 是一種輕量級的任務非同步類,可以在後檯子線程執行任務,且將執行進度及執行結果傳遞給 UI 線程。
(1)onPreExecute()
在 UI 線程上工作,在任務執行 doInBackground() 之前調用。此步驟通常用於設置任務,例如在用戶界面中顯示進度條。
(2)doInBackground(Params... params)
在子線程中工作,在 onPreExecute() 方法結束後執行,這一步被用於在後台執行長時間的任務,Params 參數通過 execute(Params) 方法被傳遞到此方法中。任務執行結束後,將結果傳遞給 onPostExecute(Result) 方法,同時我們可以通過 publishProgress(Progress) 方法,將執行進度發送給 onProgressUpdate(Progress) 方法。
(3)onProgressUpdate(Progress... values)
在 UI 線程上工作,會在 doInBackground() 中調用 publishProgress(Progress) 方法後執行,此方法用於在後台計算仍在執行時(也就是 doInBackgound() 還在執行時)將計算執行進度通過 UI 顯示出來。例如,可以通過動畫進度條或顯示文本欄位中的日誌,從而方便用戶知道後台任務執行的進度。
(4)onPostExecute(Result result)
在 UI 線程上工作,在任務執行完畢(即 doInBackground(Result) 執行完畢)並將執行結果傳過來的時候工作。
使用規則:
(1)AsyncTask 是個抽象類,所以要創建它的子類實現抽象方法
(1)AsyncTask 類必須是在 UI 線程中被載入,但在Android 4.1(API 16)開始,就能被自動載入完成。
(2)AsyncTask 類的實例對象必須在 UI 線程中被創建。
(3)execute() 方法必須是在 UI 線程中被調用。
(4)不要手動調用方法 onPreExecute()、onPostExecute()、doInBackground()、onProgressUpdate()
(5)任務只能執行一次(如果嘗試第二次執行,將拋出異常)。即一個AsyncTask對象只能調用一次execute()方法。
原理:
其源碼中原理還是 Thread 與 Handler 的實現,其包含 兩個線程池,一個 Handler,如下所示:
名稱類型作用
SERIAL_EXECUTOR線程池分發任務,串列分發,一次只分發一個任務
THREAD_POOL_EXECUTOR線程池執行任務,並行執行,執行的任務由 SERIAL_EXECUTOR 分發
InternalHandlerHandler負責子線程與主線程的溝通,通知主線程做 UI 工作
一方面減少了每個並行任務獨自建立線程的開銷,另一方面可以管理多個並發線程的公共資源,從而提高了多線程的效率。所以ThreadPoolExecutor比較適合一組任務的執行。Executors利用工廠模式對ThreadPoolExecutor進行了封裝。
Executors提供了四種創建ExecutorService的方法,他們的使用場景如下:
1. Executors.newFixedThreadPool()
創建一個定長的線程池,每提交一個任務就創建一個線程,直到達到池的最大長度,這時線程池會保持長度不再變化。
當線程處於空閑狀態時,它們並不會被回收,除非線程池被關閉。當所有的線程都處於活動狀態時,新任務都會處於等待狀態,直到有線程空閑出來。
只有核心線程並且不會被回收,能夠更加快速的響應外界的請求。
2. Executors.newCachedThreadPool()
創建一個可緩存的線程池,如果當前線程池的長度超過了處理的需要時,它可以靈活的回收空閑的線程,當需要增加時,它可以靈活的添加新的線程,而不會對池的長度作任何限制
線程數量不定的線程池,只有非核心線程,最大線程數為 Integer.MAX_VALUE。當線程池中的線程都處於活動狀態時,線程池會創建新的線程來處理新任務,否則利用空閑的線程來處理新任務。線程池中的空閑線程具有超時機制,為 60s。
任務隊列相當於一個空集合,導致任何任務都會立即被執行,適合執行大量耗時較少的任務。當整個線程池都處於限制狀態時,線程池中的線程都會超時而被停止。
3. Executors.newScheledThreadPool()
創建一個定長的線程池,而且支持定時的以及周期性的任務執行,類似於Timer。
非核心線程數沒有限制,並且非核心線程閑置的時候立即回收,主要用於執行定時任務和具有固定周期的重復任務。
4. Executors.newSingleThreadExecutor()
創建一個單線程化的executor,它只創建唯一的worker線程來執行任務
只有一個核心線程,保證所有的任務都在一個線程中順序執行,意義在於不需要處理線程同步的問題。
一般用於執行後台耗時任務,當任務執行完成會自動停止;同時由於它是一個服務,優先順序要遠遠高於線程,更不容易被系統殺死,因此比較適合執行一些高優先順序的後台任務。
使用步驟:創建IntentService的子類,重寫onHandleIntent方法,在onHandleIntent中執行耗時任務
原理:在源碼實現上,IntentService封裝了HandlerThread和Handler。onHandleIntent方法結束後會調用IntentService的stopSelf(int startId)方法嘗試停止服務。
IntentService的內部是通過消息的方式請求HandlerThread執行任務,HandlerThread內部又是一種使用Handler的Thread,這就意味著IntentService和Looper一樣是順序執行後台任務的
(HandlerThread:封裝了Handler + ThreadHandlerThread適合在有需要一個工作線程(非UI線程)+任務的等待隊列的形式,優點是不會有堵塞,減少了對性能的消耗,缺點是不能同時進行多個任務的處理,需要等待進行處理。處理效率低,可以當成一個輕量級的線程池來用)
❿ Android Handler使用
在日常開發中,都避免不了進行網路請求,並更新View,由於Android中主線程不可以進行耗時操作,所以我們的網路請求只能放在子線程中,又由於在子線程中不能更新UI,所以我們就需要使用Handler切換到主線程並更新UI。
在介紹Handler使用之前,我們先了解以下兩個問題。
1、為什麼主線程不能進行耗時操作?
因為如果在主線程進行耗時操作,容易出現ANR,Application Not Responding,即應用無響應,當在一定的時間內,app無法響應時就會出現ANR,並彈出一個 對話框提示應用無響應,所以我們應該避免在主線程中進行耗時操作,當我們應用出現ANR時,會在
/data/anr/目錄中生成traces.txt,我們可以通過這個文件查找錯誤信息。
2、為什麼子線程中不能更新UI?
這是因為在子線程中更新UI不是線程安全的,在Android源碼ViewRootImpl的checkThread方法中也對UI做了驗證。
基於這兩個問題,我們可以使用Handler來解決,接下來介紹Handler的基本使用。
首先創建Handler
接下來發送消息。
這個時候在handlerMessage方法中即可收到消息,獲取Message中的數據,並更新UI了。是不是很簡單。