使用Handler中遇到的問題分析

2021-08-10 08:26:46 字數 2713 閱讀 2234

相信很多童鞋在使用handler的時候肯定遇到了不少的麻煩吧,比如:

1、only one looper may be created per thread;

2、can』t create handler inside thread that has not called looper.prepare();

3、handler導致的記憶體洩漏等。

那麼今天就詳細分析一下其中的原因,以記錄又一次深深的掉入坑里無法自拔的囧態。

這個問題還是比較好查詢原因的,我們在使用的時候如果呼叫looper.prepare()兩次就會出現,通過檢視原始碼來分析:

private

static

void

prepare(boolean quitallowed)

sthreadlocal.set(new looper(quitallowed));

}

可以看到prepare方法中**非常少,首先是呼叫sthreadlocal.get()方法去取looper,如果是null說明沒有建立並儲存,然後會新建乙個looper物件,然後存入sthreadlocal物件中;如果不是null說明looper物件已經建立過了,這時候就會丟擲only one looper may be created per thread異常。可見prepare()方法不能呼叫兩次,如果呼叫兩次就會丟擲異常。

意思是不能在沒有呼叫looper.prepare()方法的執行緒中建立handler,那麼繼續通過原始碼分析:

public handler(callback callback, boolean async) 

}mlooper = looper.mylooper();

if (mlooper == null)

mqueue = mlooper.mqueue;

mcallback = callback;

masynchronous = async;

}

可見建立handler時,會去呼叫looper.mylooper()方法,而looper.mylooper()方法如下:

public

static @nullable looper mylooper()

上面我們分析過looper.prepare()方法會去建立looper物件,然後存入sthreadlocal中,而looper.mylooper()方法就是去sthreadlocal中去取looper物件。所以在沒有呼叫looper.prepare()方法的情況下,looper肯定是沒有建立的,而messagequeue(訊息佇列)又是在looper構造中去建立的;同時不斷的去messagequeue(訊息佇列)中取訊息,呼叫handler的dispatchmessage()方法,都是looper的loop()方法中去執行的。如果沒有建立looper物件,整個handler訊息機制就沒有辦法正常工作,所以在沒有呼叫looper.prepare()方法(沒有建立looper物件)會丟擲上面的異常。

大家應該會發現,平時使用handler的時候,沒有遇到上面所說的問題啊,那到底是為啥呢?

繼續分析,看**:

public

static

void

main(string args)

if (false)

// end of event activitythreadmain.

trace.traceend(trace.trace_tag_activity_manager);

looper.loop();

throw

new runtimeexception("main thread loop unexpectedly exited");

}

從activitythread的main方法中,我們可以看到裡面呼叫了looper 中的looper.preparemainlooper()方法,而這個方法中呼叫了prepare方法去建立looper物件並儲存起來了,並且main方法中還呼叫了looper.loop()方法。所以我們平時在主線程中使用不會遇到上述問題,是因為主線程中已經把我們需要做的事情做了。

在平時開發中,應該有多數人使用handler會造成記憶體洩漏,可能你還沒有察覺到。一般我們在activity中使用handler的寫法如下:

private handler handler = new handler()

};

告訴我,你是不是就是這樣寫的呢?

當使用內部類(包括匿名類)來建立handler的時候,handler物件會隱式地持有這個activity的引用。而handler通常會伴隨著乙個耗時的後台執行緒(網路載入),這個任務執行完之後,通過訊息機制通知handler,然後handler把更新到介面。但是,如果這時候任務沒執行完使用者關閉了activity,那麼這個activity就有可能在gc檢查時被**掉,而該執行緒持有handler的引用,這個handler又持有activity的引用,導致該activity無法被**掉(記憶體洩露)。

那麼使用handler導致記憶體洩露的解決方法是什麼呢?

static

class

myhandler

extends

handler

@override

public

void handlemessage(message msg)

}}

Joggler 使用中遇到的問題

1.挑u盤 使用官方提供的系統起來從u盤讀取 資源的時候發現有的u盤認不出來。後來發現是u盤分割槽的問題。因為這個系統一定要掛接 dev sdx1這個分割槽,所以需要採用hdd格式的優盤,zip的是不認的 2.ubuntu上執行o2的圖形前端不能工作 這幅是使用出廠的mmcblock0p2裡的 op...

Git Gerrit 使用中遇到的問題

1.remote rejected release refs for release no new changes 非常惱人的乙個問題。在網上做了些搜尋後,都說是許可權配置問題。但是,事實上我已經有了onwer與push許可權。當然也可能是版本問題,因為gerrit的版本是2.1.0 最終還是把 p...

mysql使用中遇到的問題

問題一 第一次mysql啟動服務失敗,未返回報錯資訊 解決方法 執行 mysqld console命令,檢視error資訊,對症下藥 但一般情況下,主要是因為mysql目錄下的data資料夾中內容不正確,解決方法有以下兩個 1.在開啟服務前執行初始化命令 mysqld initalize 然後啟動服...