一 前言
Toast在android里面弹的很多了,但是在分线程里面弹会怎么样呢? 有些同学会说,那还不是和平时一样的弹?!其实,也不尽然,不信?请继续往下面看。
二 分线程弹Toast引发的问题
如果在分线程里面直接弹Toast,比如下面这样,button点击的时候启动一个线程,弹出一个Toast:
那么就会得到一个应用程序异常终止的错误弹窗。
原因如下: 意思是如果没有调用Looper.prepare(),就不能初始化Handler对象。看错误堆栈,是Toast.makeText()的时候会初始化Handler对象。
这个调用过程如下:
1. 从Toast.makeText(...)开始
它会初始化一个Toast对象,继续看Toast的构造函数:
2.
在Toast的构造函数里面,会初始化一个TN对象,这个TN对象是什么东西呢?
3.
这个TN对象是Binder对象的子类,显而易见,它是跨进程通信用的。其实它就是和系统Toast服务通信用的,应用程序需要把自己的Toast请求发送给系统Toast服务,告诉它,我需要弹一个什么样的Toast。
所以需要TN这个东东。
而TN这个东东需要初始化Handler成员变量,所以就会调用到Handler初始化这边。
4. Handler初始化
Handler初始化的时候会拿出与当前线程相关的Looper对象,如果不存在,也就是没有调用过Looper.prepare()方法的话,就会报错。
这就是上面错误的来源啦!
三 如何解决?
知道原因后,就比较好解决了,于是就出现了下面的代码:
在分线程弹出Toast之前把Looper准备好,实验表明,这样确实可以达到效果。可以把Toast弹出来。
但是这样有个问题,就是会导致分线程永远不会退出。这个原理大家看看Looper.loop()是怎么实现的就知道了,它里面是一个死循环。
这样的话,会导致进程里面的线程越来越多,这个本人是不推荐的。
四 另外一种解决方法
除了第三种方法之外,我们还有种方法,就是把Toast丢到主线程去弹出来。
也很简单,主要初始化一个主线程的Handler,然后调用Handler.postRunnable()方法就可以了。,如下:
Toast在android里面弹的很多了,但是在分线程里面弹会怎么样呢? 有些同学会说,那还不是和平时一样的弹?!其实,也不尽然,不信?请继续往下面看。
二 分线程弹Toast引发的问题
如果在分线程里面直接弹Toast,比如下面这样,button点击的时候启动一个线程,弹出一个Toast:
那么就会得到一个应用程序异常终止的错误弹窗。
原因如下: 意思是如果没有调用Looper.prepare(),就不能初始化Handler对象。看错误堆栈,是Toast.makeText()的时候会初始化Handler对象。
这个调用过程如下:
1. 从Toast.makeText(...)开始
2.
3.
所以需要TN这个东东。
而TN这个东东需要初始化Handler成员变量,所以就会调用到Handler初始化这边。
4. Handler初始化
这就是上面错误的来源啦!
三 如何解决?
知道原因后,就比较好解决了,于是就出现了下面的代码:
在分线程弹出Toast之前把Looper准备好,实验表明,这样确实可以达到效果。可以把Toast弹出来。
但是这样有个问题,就是会导致分线程永远不会退出。这个原理大家看看Looper.loop()是怎么实现的就知道了,它里面是一个死循环。
这样的话,会导致进程里面的线程越来越多,这个本人是不推荐的。
四 另外一种解决方法
除了第三种方法之外,我们还有种方法,就是把Toast丢到主线程去弹出来。
也很简单,主要初始化一个主线程的Handler,然后调用Handler.postRunnable()方法就可以了。,如下: