Handler中post方法的調用流程和使用場景


 最近一直在學習多線程,handler的作用真的很重要啊,所以保存這篇看的蠻懂的。

 

Handler mHandler = new Handler();  
mHandler.post(new Runnable() {  
    @Override  
    public void run() {  
        showContentView(contentView);  
}  
});  

 

下面我們先來看一下這個方法是怎么執行的


首先:

public final boolean post(Runnable r)  
{  
    return  sendMessageDelayed(getPostMessage(r), 0);  
}  

 

它把Runnable重新封裝了一遍然后調用了sendMessageDelayed方法



看一下是怎么封裝的

private final Message getPostMessage(Runnable r) {  
    Message m = Message.obtain();  
    m.callback = r;  
    return m;  
}  

 

看到了吧,用過Handler的都知道Message是用來記錄信息的最小單元,這里把Runnable封裝到一個Message對象並返回





然后:

public final boolean sendMessageDelayed(Message msg, long delayMillis)  
{  
    if (delayMillis < 0) {  
        delayMillis = 0;  
    }  
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
}  

 

這里就是對delayMillis做了一下有效性檢測






緊接着:

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

 

Handler對象把Message壓到了MessageQueue隊列里面

貌似方法到這里就return了,那么壓進去的信息是怎么發送的呢? 這得從Handler的原理說起了。有很多人已經寫了這個原理了,就不在做闡述
可以查看這篇博客《android handler線程原理詳詳解》






然后我們去分發信息的點去看是如何執行的

public static final void loop() {  
        Looper me = myLooper();  
        MessageQueue queue = me.mQueue;  
        while (true) {  
            Message msg = queue.next(); // might block  
            //if (!me.mRun) {  
            //    break;  
            //}  
            if (msg != null) {  
                if (msg.target == null) {  
                    // No target is a magic identifier for the quit message.  
                    return;  
                }  
                if (me.mLogging!= null) me.mLogging.println(  
                        ">>>>> Dispatching to " + msg.target + " "  
                        + msg.callback + ": " + msg.what  
                        );  
                msg.target.dispatchMessage(msg);  
                if (me.mLogging!= null) me.mLogging.println(  
                        "<<<<< Finished to    " + msg.target + " "  
                        + msg.callback);  
                msg.recycle();  
            }  
        }  
    }  

 

Looper對象把MessageQueue里面的Message逐個取出來,注意看msg.target.dispatchMessage(msg)這一句。
Message類定義了一個字段target,這個字段就是Handler類型,存的對象就是創建這個message的對象,也就是我們的handler對象。

 

 

 

然后就是調用我們的handler里面的dispatchMessage(msg)方法了

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

 

看到沒有,一開始我們的Runnable傳進來,然后調用GetPostMessage方法把Runnable賦值給了Massage里面的callback,
在分發的時候判斷如果callback不是null就調用handleCallback(msg)方法。

 

 


最后,執行我們的線程。

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






---------------------------------------------------------小小分割線----------------------------------------------------------
意義:
到了這里,我們發現貌似這玩意也就是轉了一圈又調用了線程的run而已么,那么這又有什么用呢。
如果我們給handler傳入的是一個message,那么最后會調用我們的handler的handleMessage(Message)方法,然后我們再去判斷最后再去處理
,但是我們用runnable可以直接傳入如何操作的對象,不需要再接收到消息后再去判斷message的what然后選擇做什么操作,從代碼清晰的角度,
我也覺得這樣子會比在判斷一遍要清晰,容易理解很多。




---------------------------------------------------------小小分割線----------------------------------------------------------
所解決的問題:
請看博文第一段代碼,這里面的runnable執行了一個setContentView(View),這里的handler是在onActivityResult里面調用的,也就是注銷后重新登錄回到主頁面的這種情況,這個view里面包含了一些fragment,然后activity里面綁定fragment是需要是活動狀態的,如果不用handler,直接執行,在onActivityResult方法執行期間activity還是在onPause狀態,所以在程序執行到添加fragment的時候報錯了,而用了handler就能保證這段代碼最后會在activity處於活動狀態既UI線程里面執行了。

 

 

原文鏈接:http://blog.csdn.net/panjidong_3/article/details/7890383


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM