Handler機制原理


首先說說Handler 使用中隱藏的坑

1、delay的時間過長,導致 activity未被回收內存泄漏以及邏輯錯誤

  可以將Handler攜程static靜態內部類,或者而降handler中引用的activity位軟引用

2、new 了過多的message,導致內存泄漏,應該在處理后remove這些msg

3、Activity finish()后應該remove所有的msg和runable

 

 

------------------------------------------------------------------------------------------------------------------------------

 

各種類的含義 

Message:消息,其中包含了消息ID,消息處理對象以及處理的數據等,由MessageQueue統一列隊,終由Handler處理。

Handler:處理者,負責Message的發送及處理。使用Handler時,需要實現handleMessage(Message msg)方法來對特定的Message進行處理,例如更新UI等。

MessageQueue:消息隊列,用來存放Handler發送過來的消息,並按照FIFO規則執行。當然,存放Message並非實際意義的保存,而是將Message以鏈表的方式串聯起來的,等待Looper的抽取。

Looper:消息泵,不斷地從MessageQueue中抽取Message執行。因此,一個MessageQueue需要一個Looper。

Thread:線程,負責調度整個消息循環,即消息循環的執行場所。

------------------------------------------------------------------------------------------------------------------------------

關系

Handler,Looper和MessageQueue就是簡單的三角關系。

Looper和MessageQueue一一對應,創建一個Looper的同時,會創建一個MessageQueue。

而Handler與它們的關系,只是簡單的聚集關系,即Handler里會引用當前線程里的特定Looper和MessageQueue。

這樣說來,多個Handler都可以共享同一Looper和MessageQueue了。

這些Handler也就運行在同一個線程里,每個線程一個Loop而 一個MessageQueue。

 ------------------------------------------------------------------------------------------------------------------------------------------------------------

 使用:

子線程網主線程中發消息,直接在主線程中handler = new Handler(),子線程中可以直接用handler.sendmessage。。。

主線程網子線程中,Looper.prepare()... handler = new Handler()... looper.loop...然后handler.sendmessage

一個Message經由Handler的發送,MessageQueue的入隊,Looper的抽取,又再一次地回到Handler的懷抱

 

 

Handler的處理過程運行在創建Handler的線程里

·      一個Looper對應一個MessageQueue

·      一個線程對應一個Looper

·      一個Looper可以對應多個Handler

·      不確定當前線程時,更新UI時盡量調用post方法

 

 

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Android的主線程循環創建

  Android程序的運行入口點可以認為是android.app.ActivityThread類的main()方法(源碼2.3.3):

復制代碼
    public static final void main(String[] args) {
        // other codes...

        // 創建主線程循環
        Looper.prepareMainLooper();
        if (sMainThreadHandler == null) {
            sMainThreadHandler = new Handler();
        }

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        // other codes...

        // 進入當前線程(此時是主線程)消息循環
        Looper.loop();

        // other codes...

        thread.detach();
        // other codes...
    }
復制代碼

 

  這個main()方法里面為程序創建了主線程循環

  Looper類中的主線程創建方法prepareMainLooper()

 

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 ThreadLocal為每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。

今天用子線程調Toast報了一個Can't create handler inside thread that has not calledLooper.prepare()錯誤。


解決辦法很簡單:
Looper.prepare();

new handler...

Looper.loop();




Looper
public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
       sThreadLocal.set(new Looper());  //在當前線程中創建一個Looper
    }

private Looper() {
        mQueue = new MessageQueue();  //關鍵在這,創建Looper都干了什么。 其實是創建了消息隊列
        mRun = true;
        mThread = Thread.currentThread();
    }


一般如果不是在主線程中又開啟了新線程的話,一般都會碰到這個問題。
原因是在創建新線程的時候默認情況下不會去創建新的MessageQueue。

 


免責聲明!

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



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