亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

深入淺析Android消息機制

2019-12-12 06:41:36
字體:
來源:轉載
供稿:網友

在Android中,線程內部或者線程之間進行信息交互時經常會使用消息,這些基礎的東西如果我們熟悉其內部的原理,將會使我們容易、更好地架構系統,避免一些低級的錯誤。

每一個Android應用在啟動的時候都會創建一個線程,這個線程被稱為主線程或者UI線程,Android應用的所有操作默認都會運行在這個線程中。
但是當我們想要進行數據請求,圖片下載,或者其他耗時操作時,是不可能在這個UI線程做的,因為Android在3.0以后的版本已經禁止了這件事情,直接拋出一個異常。所以我們需要一個子線程來處理那些除UI操作的事情。

但是這個又會有一個問題,我們只能在UI線程進程UI操作,只能在子線程進行耗時操作,如果我們需要在耗時操作結束后在Android界面上顯示一個View,我們應該怎么做?我們是不可能在子線程直接刷新UI的。這時我們需要用到Android的消息機制,來實現主線程和子線程的通信。簡單來說,就是子線程獲取到數據之后,不直接進行UI更新,而是把數據裝到消息中發送到主線程,主線程中有一個循環輪詢會立即收到子線程發過來的信息,然后拿到消息數據后在主線程更新UI 。說起來比較簡單,我們來仔細的看一下具體是怎么說的。

處理消息的手段――Handler, Looper, MessageQueue

Handler

我們先講解一下Handler,Handler顧名思義就是處理者,通常對他的用法是在UI線程中新建一個Handler,并覆寫他的handleMessage, 然后再耗時的線程中將消息post給UI線程,例子如下:

class MyHandler extends Handler{@Overridepublic void handleMessage(Message msg){//更新UI}}MyHandler mHandler = new MyHandler();new Thread(){public void run(){mHandler.sendEmptyMessage(123);};}.start(); 

這里規定了Handler必須在主線程創建,因為只有在UI線程創建才會讓Handler關聯到已有的MessageQueue。而MessageQueue被封裝到Looper中,而Looper又通過ThreadLocal封裝到一個線程中,最后相當于MessageQueue關聯了一個線程。所以簡單來說就是Handler將消息投遞到一個關聯了線程的MessageQueue中,然后Handler在從MessageQueue中取出消息,并且處理它。

我們看一下Handler的2個常用的方法

void handleMessage(Message msg) : 處理消息的方法final boolean sendMessage(Message msg) : 立即發送消息

第一個方法 我們通常在UI線程中執行,一般用來刷新UI,至于如果創建了一個非靜態內部類產生對內存泄漏,建議參考這篇博客Handler引發的內存泄漏.第二個方法我們通常在子線程中執行,需要一個Handler的實例化對象,通常是由主線程去去傳遞給子線程。并且需要一個Message對象,指定他的msg.what作為消息的標示,但是如果我們只是用Handler去處理一個消息的時候,選擇post方法是個更好的選擇,例子如下:

private Handler mHandler = new Handler();new Thread(new Runnable() {@Overridepublic void run() {mHandler.post(new Runnable() {@Overridepublic void run() {//UI操作...}});}}).start(); 

下面我們接著討論下消息的循環隊列MessageQueue與包裝他的Looper循環

Looper和MessageQueue

上面提到了在UI線程中創建并實例化Handler對象不需要Looper和MessageQueue,因為我們的應用在啟動的時候先執行了ActivityThreadMain,在這個方法就是Java語言運行的入口public

static void main(String [] args) 在這里面創建了一個MainLooper,創建的過程如下:public static void main(string[] args){//初始化Looper.prepareMainLooper();ActivityThread thread = new ActivityThread();thread.attach(false);if(sMainThreadHandler == null){sMainThreadHandler = thread.getHandler();}AsyncTask.init();//動起來Looper.loop();} 

這里面并沒有MessageQueue的出現,我們可以看一看Looper類的源碼,來了解在初始化的時候發生了什么有趣的事情。

public class Looper {private static final ThreadLocal sThreadLocal = new ThreadLocal();// Looper內的消息隊列final MessageQueue mQueue;// 當前線程Thread mThread;// 。。。其他屬性// 每個Looper對象中有它的消息隊列,和它所屬的線程private Looper() {mQueue = new MessageQueue();mRun = true;mThread = Thread.currentThread();}// 我們調用該方法會在調用線程的TLS中創建Looper對象public static final void prepare() {if (sThreadLocal.get() != null) {// 試圖在有Looper的線程中再次創建Looper將拋出異常throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper());}// 其他方法} 

我們一行行的看這段代碼,首先是實例化一個ThreadLocal對象,這個用來實現Looper循環的本地化存儲,關于ThreadLocal可以看這篇文章為什么用ThreadLocal,簡而言之就是當多個線程同時訪問Looper對象的時候,我們不用synchronized同步機制來處理他,而是為每個線程創建一個自己的Looper副本,A線程改變了A的looper副本,不影響B線程的Looper,從而比較高效的實現線程安全。后面幾句依次定義了MessageQueue,并對Looper進行了私有化構造,在prepare方法中將Looper對象設置給了sThreadLocal 這樣MessageQueue包裝在了Looper對象中,同時通過ThreadLocal使得線程和Looper關聯上,從而消息隊列與線程關聯上,并且不同的線程就不能訪問對方的消息隊列。

如下圖所示:

接著就是Looper.loop 循環執行起來,我們看一下,在loop方法里面執行了發生了什么事情

public static final void loop() {Looper me = myLooper(); //得到當前線程LooperMessageQueue queue = me.mQueue; //得到當前looper的MQwhile (true) {Message msg = queue.next(); // 取出messageif (msg != null) {if (msg.target == null) {return;}msg.target.dispatchMessage(msg);msg.recycle();}}}

這是省略版的代碼,我們從這里看出無限循環執行,首先從消息隊列中不斷取出消息,然后不斷msg是否為空,msg.target是否為空,不空的話,執行dispatchMessage方法,這個方法是handler的一個方法,由此我們可以看出msg.target是handler的類型,至此,通過Looper.prepare和Loop.loop實現了MessageQueue,Looper,Handler三者之間的關聯。而Handler與Looper,和MessageQueue關聯則是在Handler的默認構造器中,通過Looper.getLooper獲取loop對象,從而獲取MessageQueue,其源碼如下:

public Handler(){//直接把關聯looper的MQ作為自己的MQ,因此它的消息將發送到關聯looper的MQ上mLooper = Looper.myLooper();mQueue = mLooper.mQueue;mCallback = null;}

然后我們的流程圖可以多些內容,如下所示:

我們接下來看一下dispatchMessage() 方法,在該方法中實際上只是一個分發方法,如果Runable類型的callback為空,則執行handlerMessage來處理消息,該方法為空,需要覆寫。如果不為空,則執行handleCallback。實際上,如果我們用handle的post方法,則就執行了callback,如果用sendMessage,則就執行了handleMessage
這里無論是post(Runnable callback)還是handlerMessage實際上都是在調用一個方法sendMessageDelayed(Message msg) 只不過handlerMessage是直接接受一個參數,而Runable callback實際上是將這個Runable對象賦給了Message對象的callback成員變量,最后將Message對象插入消息隊列里面。最后Looper不斷從MessageQueue中讀取消息,并且調用Handler的dispatchMessage消息,在根據callback是否為空,來采用不同的方法執行。Android消息機制分析到此結束。

回到最開始

我們這次知道了為什么要在主線程中實例化Handler對象才能更新UI刷新,因為只有發送到UI線程的消息,才能被UI線程的handler處理,如果我們要在非UI線程中,實例化Handler,則必須先將線程變成LooperThread,在實例化。也就是說執行如下的代碼:

Loop.prepare();hander = new Handler;

Loop.loop

至于原因相信讀完上面的講解,應該知道。
現在我們看一下我們最開始的代碼,最后腦補一下Handler的工作流程。

class MyHandler extends Handler{@Overridepublic void handleMessage(Message msg){//更新UI}}MyHandler mHandler = new MyHandler();new Thread(){public void run(){mHandler.sendEmptyMessage(123);};}.start(); 

在Handler實例化成mHandler的時候,系統通過Handler默認的構造函數完成了Handler與Looper的關聯,并通過Looper關聯到了MessageQueue。而主線程的Looper則早在系統啟動的時候通過Loop.prepare就已經構造完成了,并與UI線程通過ThreadLocal關聯起來,然后在新的線程中執行mHandler.sendEmptyMessage,將Message發送給了MessageQueue,Looper.loop在循環的時候,不斷取出message,交給Handler處理,在我們覆寫的HandleMessage中,識別出我們發送的消息,將消息處理。當然這里只是一個Empty消息,所以在handleMessage中沒有去執行msg.what的判斷。

以上內容是小編給大家介紹的Android消息機制,希望對大家有所幫助!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩高清av在线| 国产精品成av人在线视午夜片| 亚洲精品国产欧美| 亚洲欧美国产精品久久久久久久| 欧美在线视频观看免费网站| 成人免费看片视频| 国产精品com| 久久夜精品va视频免费观看| 国产一区二区黄| 伊人伊人伊人久久| 欧美体内谢she精2性欧美| 日韩高清中文字幕| 57pao国产精品一区| 国产精品久久久久久久电影| 黑人巨大精品欧美一区二区| 成人在线中文字幕| 欧美日本在线视频中文字字幕| 久久精品国产亚洲| 亚洲国产精品成人精品| 国内精品久久久久久久久| 成人午夜在线视频一区| 国产极品精品在线观看| 久久99热精品这里久久精品| 成人www视频在线观看| 久久不射热爱视频精品| 欧美日韩福利视频| 国产亚洲一区二区在线| 欧美亚洲视频在线看网址| 高清欧美电影在线| 久久人人爽人人爽人人片av高清| 亚洲开心激情网| 久色乳综合思思在线视频| 91久久精品国产91久久| 亚洲最新av网址| 亚洲色图在线观看| 国产视频精品在线| 91在线视频一区| 欧美精品在线极品| 亚洲已满18点击进入在线看片| 欧美另类暴力丝袜| 国产精品久久久久久久久粉嫩av| 日本精品免费一区二区三区| 日韩av理论片| 亚洲午夜国产成人av电影男同| 精品香蕉在线观看视频一| 精品亚洲一区二区三区在线观看| 在线播放精品一区二区三区| 亚洲成人网在线| 91黑丝高跟在线| 欧美做受高潮电影o| 亚洲韩国青草视频| 欧美日韩成人黄色| 亚洲欧美日韩精品| 久久精品视频导航| 搡老女人一区二区三区视频tv| 色噜噜久久综合伊人一本| 国产激情久久久久| 日韩国产欧美精品在线| 日韩亚洲精品视频| 亚洲欧美日韩爽爽影院| 日韩av成人在线| 不卡av电影院| 国产精品男人爽免费视频1| 国产欧美精品在线| 国产精品wwwwww| 国产精品久久久久久久一区探花| 欧美大学生性色视频| 久久色精品视频| 国产精品6699| 国产精品自拍偷拍视频| 成人黄色中文字幕| 91九色单男在线观看| 欧美—级a级欧美特级ar全黄| 久久成人18免费网站| 久久免费精品日本久久中文字幕| 国产精品第一页在线| www国产精品com| 久久久久久久久久久久久久久久久久av| 搡老女人一区二区三区视频tv| 91国产美女在线观看| 另类美女黄大片| 日韩av电影在线免费播放| 亚洲日韩中文字幕| 久久久噜噜噜久久久| 国产成人精品999| 97欧美精品一区二区三区| 久久人人爽人人爽人人片亚洲| 国产suv精品一区二区三区88区| 亚洲欧美日韩天堂一区二区| 日韩欧美在线网址| 国产精品成人一区二区| 亚洲精品久久视频| 国产欧美一区二区白浆黑人| 欧美一级片免费在线| 亚洲国产精品久久| 福利微拍一区二区| 成人av在线天堂| 日韩中文字幕视频在线| 国产做受69高潮| 欧美黑人xxx| 日韩风俗一区 二区| 久热精品视频在线| 亚洲第一色在线| 国产亚洲成av人片在线观看桃| 日韩麻豆第一页| 国产精品久久久久久一区二区| 这里只有精品在线观看| 久久五月天色综合| 欧美激情免费视频| 亚洲一区二区三区视频播放| 亚洲精品久久久久中文字幕欢迎你| 色悠久久久久综合先锋影音下载| 亚洲国产精品高清久久久| 欧美成aaa人片在线观看蜜臀| 91嫩草在线视频| 欧美一区二区三区精品电影| 中文字幕日韩欧美在线视频| 国产在线98福利播放视频| 久久综合色88| 亚洲最大成人网色| 亚洲视频欧洲视频| 色哟哟入口国产精品| 亚洲成人黄色在线观看| 精品福利一区二区| 国产亚洲精品一区二555| 成人性教育视频在线观看| 91精品国产99久久久久久| 神马国产精品影院av| 按摩亚洲人久久| 国产mv免费观看入口亚洲| 久久精品电影网站| 欧美亚洲成人精品| 日韩精品在线影院| 庆余年2免费日韩剧观看大牛| 亚洲电影免费观看高清完整版在线观看| 欧美性受xxxx黑人猛交| 亚洲在线视频观看| 久久精品电影一区二区| 亚洲高清av在线| 亚洲精品videossex少妇| 国产亚洲一区二区在线| www高清在线视频日韩欧美| 国产91免费观看| 亚洲最大中文字幕| 亚洲欧美成人一区二区在线电影| 亚洲一区二区三区四区在线播放| 中国china体内裑精亚洲片| 国产精品∨欧美精品v日韩精品| 成人精品一区二区三区电影黑人| 91po在线观看91精品国产性色| 久久成人人人人精品欧| 国产一区二区三区四区福利| 欧美精品久久久久a| 日韩av影视综合网| 91久久精品国产91久久性色| 91成人在线播放| 国产精品美女午夜av| 国产精品久久久久一区二区| 日韩在线观看免费高清| 国内精品美女av在线播放| 夜夜狂射影院欧美极品| 国产精品久久久久久久久久三级| 亚洲精品国产精品自产a区红杏吧| 中文字幕在线成人|