问题:
在开发过程中,有如下需求,需要在协议层的最底层将服务器返回的错误信息toast出来,告知用户此次请求的错误,可是协议层底层是一个类,它没有上下文参数(context),按正常思路就是将context参数从activity层往下传到需要context的层,可是目前工程的框架已经定下来,从activity到协议层有四五层,这样一层一层地传费时,并且要将工程所有的activity都加一遍,这个工程量是非常巨大的!于是查询了一些资料,试一下能否使用全局的context来toast。
使用了myapplication保存下来的context,发现报错了Can't create handler inside thread that has not called Looper.prepare()
一般来说toast是要运行在activity才能够show出来,这次使用了全局的context显然是不行的。看一下toast的内部机制
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();
}
一般如果不是在主线程中又开启了新线程的话,一般都会碰到这个问题。
原因是在创建新线程的时候默认情况下不会去创建新的MessageQueue。
主线程能够toast是因为安卓封装过程中,将一个消息队列跟activity绑定了,所以可以直接使用toast.show()
于是只要在我们的代码中加上
Looper.prepare();
Toast.makeText(getApplicationContext(), "test", Toast.LENGTH_LONG).show();
Looper.loop();
Looper.myLooper().quit();即可
总结下:Toast 显示的必要条件:
Toast 显示需要出现在一个线程的消息队列中