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

错误

使用子线程调用Toast报Can’t create handler inside thread that has not calledLooper.prepare()错误。

原因

toast的实现需要在activity的主线程才能正常工作,传统的非主线程不能使toast显示在actvity上,只能通过Handler可以使自定义线程运行于Ui主线程。

解决方法
Looper.prepare();
Toast.makeText(getApplicationContext(), "message", Toast.LENGTH_LONG).show();
Looper.loop();
解释
Toast 
    public void show() {
      ...
        service.enqueueToast(pkg, tn, mDuration);   //把这个toast插入到一个队列里面
      ...
    }

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();
    }


    如果需要在子线程中使用Handler类,首先需要创建Looper类实例,这时可以通过Looper.prepare()和Looper.loop()函数来实现的。
    阅读Framework层源码发现,Android为我们提供了一个HandlerThread类,该类继承Thread类,并使用上面两个函数创建Looper对象,而且使用wait/notifyAll解决了多线程中子线程1获取子线程2的Looper对象为空的问题。
    Toast创建时需要创建一个Handler,但是这个Handler需要获得Looper的实例,而在子线程中是没有这个实例的,需要手动创建。


    一般如果不是在主线程中又开启了新线程的话,一般都会碰到这个问题。
    原因是在创建新线程的时候默认情况下不会去创建新的MessageQueue。

你可能感兴趣的:(Android)