子线程调用Toast报Can‘t create handler inside thread that has not calle
一、前言
原子线程调用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主线程。
前几次碰到这个问题,确实郁闷了很久...
二、解决方案
解决办法很简单:
为什么要加这两句,看了源码就了解了
Toast
Looper
一般如果不是在主线程中又开启了新线程的话,一般都会碰到这个问题。
原因是在创建新线程的时候默认情况下不会去创建新的MessageQueue
。
总结下:Toast 显示的必要条件:Toast 显示需要出现在一个线程的消息队列中.... 很隐蔽
三、Android中HandlerThread类的解释
Android应用中的消息循环由Looper和Handler配合完成,Looper类用于封装消息循环,类中有个MessageQueue
消息队列;Handler类封装了消息投递和消息处理等功能。
系统默认情况下只有主线程(即UI线程)绑定Looper对象,因此在主线程中可以直接创建Handler的实例,但是在子线程中就不能直接new出Handler的实例了,因为子线程默认并没有Looper对象,此时会抛出RuntimeException异常:
浏览下Handler的默认构造函数就一目了然了:
如果需要在子线程中使用Handler类,首先需要创建Looper类实例,这时可以通过Looper.prepare()和Looper.loop()函数来实现的。阅读Framework层源码发现,Android为我们提供了一个HandlerThread类,该类继承Thread类,并使用上面两个函数创建Looper对象,而且使用wait/notifyAll解决了多线程中子线程1获取子线程2的Looper对象为空的问题。
Toast创建时需要创建一个Handler,但是这个Handler需要获得Looper的实例,而在子线程中是没有这个实例的,需要手动创建。
附Toast部分源码:
Handler源码:
- 点赞
- 收藏
- 关注作者
评论(0)