線程間通信使用handler,爲什麼創建handler前要調用Looper.prepare()方法。

問題:創建handler前如果不調用Looper.prepare()會異常閃退。

Handler handler = new Handler();
來看Handler的默認構造方法:
public Handler() {
    this(null, false);//這個就是下面的這個方法 一個callback參數 一個boolean參數
}

public Handler(@Nullable Callback callback, boolean async) {
...省略部分代碼
    mLooper = Looper.myLooper(); //拿到Looper對象
//如果mLooper對象爲空的,那麼直接一個運行時異常報錯 然後退出程序
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
}

再看Looper.myLooper()裏面做了什麼事情:

public static @Nullable Looper myLooper() {
// sThreadLocal是一個ThreadLocal實例。不做重點介紹,只要知道它是保證每個線程只能有一個Looper對象就可以了。(這裏有個疑惑爲什麼每個線程只能有一個Looper對象?谷歌大哥爲什麼要這樣設計?看這裏 https://blog.csdn.net/qq_40207976/article/details/105723076 )
//通過sThreadLocal拿到Looper對象。
 return sThreadLocal.get();
}
//既然會get到null的Looper。 那麼我們來看看Looper是怎麼set進去的? Looper.prepare()上場了。來看下面👇兩個方法
public static void prepare() {
    prepare(true);//這裏執行的就是下面這個方法。
}

private static void prepare(boolean quitAllowed) {
//如果sThreadLocal.get()返回的不爲null 那麼程序就會報錯掛掉。 
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
//如果sThreadLocal.get()返回值爲null. 那麼就實例化一個Looper 然後set進去。 如果執行了下面這句,你再Looper.prepare()一次,那麼程序也會掛掉,所以:這裏我們也可以知道,Looper.prepare()同一線程不可以使用兩次,否則程序會掛掉
    sThreadLocal.set(new Looper(quitAllowed));
}

 

總結:

創建handler前如果不調用Looper.prepare();  handler的構造方法中的Looper.myLooper()就拿不到Looper對象,就會報運行時異常。所以創建handler前必須要調用一次Looper.prepare() 而且也只能調用一次,如果調用多次的話 程序也會報運行時異常 掛掉。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章