国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Handler,MessageQueue,Looper

2019-11-09 14:44:45
字體:
來源:轉載
供稿:網友

深入理解Handler,MessageQueue,Looper 轉:http://www.jianshu.com/p/6d143b8c15ee 前言: 其實講 Handler 內部機制的博客已經很多了,但是自己還是要在看一遍,源碼是最好的資料。在具體看源碼之前,有必要先理解一下 Handler、Looper、MessageQueue 以及 Message 他們的關系。 Looper: 是一個消息輪訓器,他有一個叫 loop() 的方法,用于啟動一個循環,不停的去輪詢消息池 MessageQueue: 就是上面說到的消息池 Handler: 用于發送消息,和處理消息 Message: 一個消息對象

源碼分析開始: 一切要從Handler的構造函數開始講起

public Handler(Callback callback, boolean async) { mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.我們可以看到,Handler定義了一個MessageQueue對象mQueue和一個Looper對象mLooper。順著源碼繼續往下看,跳轉到Looper.myLooper()方法。

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();public static @Nullable Looper myLooper() { return sThreadLocal.get();}

這里涉及了ThreadLocal,暫時不講。通過ThreadLocal的get方法獲取Looper并返回。那么問題來了?我們只看到了get,并沒有看到set。如果沒有set的話,get出來就會為null,通過Handler的構造函數我們知道,mLooper==null會拋出異常。而我們在使用Handler的過程中并沒有遇到該異常。那問題來了,到底在哪里進行了set呢?通過對Looper源碼搜索發現,改方法進行set操作:

private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed));}

可以看到在prepare()方法中進行了set操作,那么問題又來了,哪里調用了該方法呢?因為prepare方法是私有方法,所以肯定是本類中調用,通過搜索發現以下方法調用了prepare()方法:

* Initialize the current thread as a looper, marking it as an *
application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself. See also: {@link #prepare()} */public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); }}

那一切就是順利成章了。到這里,有人又會問,那這個方法又是誰調用的呢?看注釋發現,該方法在啟動app的時候就已經調用了。具體是在ActivityThread的main方法中啟動。 到這里為止,我們了解了Handler,Looper的初始化相關知識。接下來,我們需要了解的是如何進行發送和處理Message。 發送Message代碼如下:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis);}

這個方法我們主要是看enqueueMessage():

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);}

這里關鍵的是看懂msg.target = this;msg就是Message的對象,那么看Message源碼發現,它的target屬性是Handler target;那么,為什么發送消息的時候需要將this(當前Handler對象)帶過去呢?咋們暫且繼續… 這個方法實際執行的還是queue.enqueueMessage(),我們找到MessageQueue類的相關方法,發現以下代碼 msg.next = p; // invariant: p == prev.next prev.next = msg; 通過這兩行代碼我們發現,MessageQueue并不是隊列,而是單鏈表。所以下次面試的時候,如果你支出handler的消息隊列其實是利用Message的單鏈表實現的肯定能加分的。 到此,發送消息已經講完了。下面我們看看處理消息是怎樣進行的呢?我們知道,Loope會從MessageQueue中不斷拿消息,我們看看Looper.loop()代碼:

public static void loop() { for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } msg.target.dispatchMessage(msg); msg.recycleUnchecked(); }}

這里取出消息并分發之。是不是有頓悟的感覺,回到上面我們遺留的問題:msg.target = this,將this傳遞過去,言外之意就是哪個Handler發送的消息就由哪個Handler進行處理。那么我們來看看Handler的dispatchMessage 方法:

public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); }}

終于見到我們最常見的handleMessage()了。他首先判斷 Message 對象的 callback 對象是不是為空,如果不為空,就直接調用 handleCallback 方法,并把 msg 對象傳遞過去,這樣消息就被處理了,我們來看 Message 的 handleCallback 方法

private static void handleCallback(Message message) { message.callback.run();}

沒什么好說的了,直接調用 Handler post 的 Runnable 對象的 run() 方法。 如果在發送消息時,我們沒有給 Message 設置 callback 對象,那么程序會執行到 else 語句塊,此時首先判斷 Handler 的 mCallBack 對象是不是空的,如果不為空,直接調用 mCallback 的 handleMessage 方法進行消息處理。最終,只有當 Handler 的 mCallback 對象為空,才會執行自己的 handleMessage 方法。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 梁平县| 东平县| 台湾省| 五寨县| 吉林市| 仁布县| 磴口县| 宁陵县| 禹州市| 茂名市| 天全县| 西畴县| 固安县| 通辽市| 滦平县| 新巴尔虎左旗| 曲沃县| 双鸭山市| 长丰县| 新巴尔虎右旗| 瑞金市| 芦溪县| 北京市| 肥西县| 苍山县| 会东县| 云浮市| 绵阳市| 页游| 商河县| 全州县| 新和县| 绿春县| 池州市| 三门县| 曲周县| 读书| 额敏县| 阿鲁科尔沁旗| 高要市| 寿光市|