线程间通信使用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() 而且也只能调用一次,如果调用多次的话 程序也会报运行时异常 挂掉。

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