Toast show的时候崩溃的问题
来源:互联网 发布:今日头条mac客户端 编辑:程序博客网 时间:2024/04/30 06:20
今天同事提交了一份代码,里面有一个简单的Toast.makeText(`````).show(),没想到真正运行的时候跑到这里挂掉了:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
从崩溃上看这是looper没有启动导致的,但是为什么? 查询源码后找到了原因(以6.0源码为例):
先看Toast的show方法:
/** * Show the view for the specified duration. */ public void show() { if (mNextView == null) { throw new RuntimeException("setView must have been called"); } INotificationManager service = getService(); String pkg = mContext.getOpPackageName(); TN tn = mTN; tn.mNextView = mNextView; try { service.enqueueToast(pkg, tn, mDuration); } catch (RemoteException e) { // Empty } }
这里直接交给了INotificationManager来进行显示的操作,按照android的命名规则,这个AIDL的实现位于NotificationManagerService中:
<span style="white-space:pre"></span>@Override public void enqueueToast(String pkg, ITransientNotification callback, int duration) { ...... synchronized (mToastQueue) { int callingPid = Binder.getCallingPid(); long callingId = Binder.clearCallingIdentity(); try { ToastRecord record; int index = indexOfToastLocked(pkg, callback); // If it's already in the queue, we update it in place, we don't // move it to the end of the queue. if (index >= 0) { record = mToastQueue.get(index); record.update(duration); } else { // Limit the number of toasts that any given package except the android // package can enqueue. Prevents DOS attacks and deals with leaks.
<span style="white-space:pre"></span>...... record = new ToastRecord(callingPid, pkg, callback, duration); mToastQueue.add(record); index = mToastQueue.size() - 1; keepProcessAliveLocked(callingPid); } // If it's at index 0, it's the current toast. It doesn't matter if it's // new or just been updated. Call back and tell it to show itself. // If the callback fails, this will remove it from the list, so don't // assume that it's valid after this. if (index == 0) { showNextToastLocked(); } } finally { Binder.restoreCallingIdentity(callingId); } } }
一系列的判断后,交给了showNextToastLocked方法:
void showNextToastLocked() { ToastRecord record = mToastQueue.get(0); while (record != null) { if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); try { record.callback.show(); scheduleTimeoutLocked(record); return; } catch (RemoteException e) { Slog.w(TAG, "Object died trying to show notification " + record.callback + " in package " + record.pkg); // remove it from the list and let the process die int index = mToastQueue.indexOf(record); if (index >= 0) { mToastQueue.remove(index); } keepProcessAliveLocked(record.pid); if (mToastQueue.size() > 0) { record = mToastQueue.get(0); } else { record = null; } } } }
最终的展示是在这句:record.callback.show(),这个record.callback其实是由Toast通过AIDL传递过来的,回头再看Toast的代码,其实是调用了一个内部类TN.show():
/** * schedule handleShow into the right thread */ @Override public void show() { if (localLOGV) Log.v(TAG, "SHOW: " + this); mHandler.post(mShow); }而这个mHandler也就是我们报错时所提示的looper所在,它的创建就是一句简单的new而已:
private static class TN extends ITransientNotification.Stub {
<span style="white-space:pre"></span>......
<span style="white-space:pre"></span>private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(); final Handler mHandler = new Handler();
<span style="white-space:pre"></span>
}
至此也就搞清楚了这个崩溃的根本原因了,运行Toast.show()的线程,自身的looper并没有开始工作,所以导致了这个崩溃。
0 0
- Toast show的时候崩溃的问题
- actionBar.show()崩溃问题
- MKMapView释放的时候崩溃
- Toast的context问题
- JVM 调试的的时候崩溃
- 当程序崩溃的时候怎么办 iphone
- 当程序崩溃的时候怎么办 iphone
- 当程序崩溃的时候怎么办 iphone
- 当程序崩溃的时候怎么办
- 当程序崩溃的时候怎么办
- 当程序崩溃的时候怎么办 EXC_BAD_ACCESS
- 本地化数据字典的时候出现崩溃
- 切换VC的时候内存溢出崩溃
- 使用UISearchController的时候 cellForRow 崩溃
- 程序崩溃的时候得到CallStack
- 趣拍SDK的使用其他颜色渲染,和第二次录制的时候会崩溃问题
- Android 当使用相机并截取照片的时候程序崩溃的问题
- ExtAudioFileSetProperty 崩溃的问题
- css布局之三列布局中间自适应
- u3d honey hex framework 路径显示改造
- 优化反射性能的总结(上)
- MFC对话框及窗口函数调用顺序
- kernel 启动流程之 【设备驱动加载】 学习笔记
- Toast show的时候崩溃的问题
- Shell输入输出重定向:Shell Here Document,/dev/null文件
- Java常用GoF设计模式之一模板模式
- 优化反射性能的总结(中)
- mysql锁 实战测试代码
- Android 微信支付
- Word每页插入一张图片相关问题
- iOS SQLite加密之SQLCipher
- hdu2082找单词(背包)