Can‘t create handler inside thread that has not called Looper.prepare()

Posted 阳光照不到的王国

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Can‘t create handler inside thread that has not called Looper.prepare()相关的知识,希望对你有一定的参考价值。

 

 

android开发过程中,如果在子线程中创建Handler时会出现下面这种异常。

Can't create handler inside thread that has not called Looper.prepare()

下面根据源码来解读下出现这个问题的原因

Handler所在的目录位置

/frameworks/base/core/java/android/os/Handler.java

1、Handler的构造函数

  public Handler() {
        //注释1
        this(null, false);
    }


    //注释2
    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
        //注释3
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

注释1:在new Handler()时会调用注释2处的两个参数的构造函数。

下面观察注释3处,通过Looper.myLooper()来获取mLooper对象,如果mLooper对象为空则抛出此文章开头时出现的异常。

2、查看Looper.myLooper()函数做了什么。

Looper类对应Android源码目录如下

/frameworks/base/core/java/android/os/Looper.java

返回一个与当前线程关联的Looper对象,如果当前线程未关联Looper则返回null。

继续查看sTheadLocal。如果没有调用prepare()的话,sTheadLocal.get()将会返回null

看下prepare()函数

根据源码可以看出,调用prepare()函数之后才会调用sThreadLocal.set(Looper)。

走到这个步骤之后也就基本破案了,解决方法也一目了然。就是在子线程中创建Handler之前要调用一下Looper.prepare();

 

以上是关于Can‘t create handler inside thread that has not called Looper.prepare()的主要内容,如果未能解决你的问题,请参考以下文章