在子线程中Toast了一把,竟然报错
因为Toast在service和activity中都可以执行。所以开始就认为和ui线程没有有太大的关系,现在在子线程使用Toast竟然报错!
后来查看Toast的源码,写了个demo,报错非常的清楚,终于搞定了。
05-12 15:55:36.761 13374-13981/yzx.demo.com.demo E/AndroidRuntime: FATAL EXCEPTION: Thread-2578
Process: yzx.demo.com.demo, PID: 13374
java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()
at android.os.Handler.(Handler.java:200)
at android.os.Handler.(Handler.java:114)
at yzx.demo.com.demo.MainActivity
CalThread
1.(MainActivity.java:0)
at yzx.demo.com.demo.MainActivity$CalThread.run(MainActivity.java:71)
1、错误的关键位置在于Toast初始化的时候,这句
public class Toast {final Handler mHandler = new Handler();….}
2、其实在别的地方也看到过,普通线程不能直接new一个Handler
原因:
public Handler(){
…..
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
…..
}
3、而Looper中
public static final Looper myLooper() {
//这个方法是从当前线程的ThreadLocal中拿出设置的looper
return (Looper)sThreadLocal.get();
}
而事实上子线程只是一个普通的线程,其ThreadLoacl中没有设置过Looper,所以会抛出异常
4、解决方法:子线程要想使用toast,其实源码中需要创建handler,那么就需要先Looper。prepare() 然后使用toast 然后调用Looper.loop();就可以正常使用toast了~
public void onClick(View v) {
new Thread(){
public void run() {
Log.i("log", "run");
Looper.prepare();
Toast.makeText(ActivityTestActivity.this, "toast", 1).show();
Looper.loop();// 进入loop中的循环,查看消息队列
};
}.start();
}
Looper.prepare()方法参考
//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());
}