稍微纤细一点儿的信息是: Handler (android.os.Handler) {215ddea8} sending message to a Handler on a dead thread。java
在另外一次在IntentService里使用MediaPlayer 播放铃声也再现错误,信息是:Handler) {42414500} sending message to a Handler on a dead thread。android
本次的完整信息是:app
W/ActivityManager( 1394): getTasks: caller 10034 is using old GET_TASKS but privileged; allowing W/MessageQueue( 7666): Handler (android.os.Handler) {215ddea8} sending message to a Handler on a dead thread W/MessageQueue( 7666): java.lang.IllegalStateException: Handler (android.os.Handler) {215ddea8} sending message to a Handler on a dead thread W/MessageQueue( 7666): at android.os.MessageQueue.enqueueMessage(MessageQueue.java:325) W/MessageQueue( 7666): at android.os.Handler.enqueueMessage(Handler.java:635) W/MessageQueue( 7666): at android.os.Handler.sendMessageAtTime(Handler.java:604) W/MessageQueue( 7666): at android.os.Handler.sendMessageDelayed(Handler.java:574) W/MessageQueue( 7666): at android.os.Handler.postDelayed(Handler.java:398) W/MessageQueue( 7666): at com.bandwidthx.library.l.a(SourceFile:367) W/MessageQueue( 7666): at com.bandwidthx.library.l.B(SourceFile:357) W/MessageQueue( 7666): at com.bandwidthx.library.BxApproval.aZ(SourceFile:4563) W/MessageQueue( 7666): at com.bandwidthx.library.BxApproval.aT(SourceFile:4440) W/MessageQueue( 7666): at com.bandwidthx.library.BxApproval.aS(SourceFile:4431) W/MessageQueue( 7666): at com.bandwidthx.library.BxApproval.aG(SourceFile:4044) W/MessageQueue( 7666): at com.bandwidthx.library.l.a(SourceFile:1320) W/MessageQueue( 7666): at com.bandwidthx.library.l.j(SourceFile:1275) W/MessageQueue( 7666): at com.bandwidthx.library.q.w(SourceFile:2280) W/MessageQueue( 7666): at com.bandwidthx.library.q.a(SourceFile:3399) W/MessageQueue( 7666): at com.bandwidthx.library.q.a(SourceFile:3103) W/MessageQueue( 7666): at com.bandwidthx.library.q$1.a(SourceFile:1959) W/MessageQueue( 7666): at com.bandwidthx.library.q$1.doInBackground(SourceFile:1928) W/MessageQueue( 7666): at android.os.AsyncTask$2.call(AsyncTask.java:292) W/MessageQueue( 7666): at java.util.concurrent.FutureTask.run(FutureTask.java:237) W/MessageQueue( 7666): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) W/MessageQueue( 7666): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) W/MessageQueue( 7666): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) W/MessageQueue( 7666): at java.lang.Thread.run(Thread.java:818)
估计Looper啊,MessageQueue之类的,已经被大家说烂了。ide
我就简单归纳一句(固然下面也有很详细的)oop
一旦一个线程的消息循环退出后,不能再给其发送消息,不然会有RuntimeException抛出。
就是你通常性看到的:post
"RuntimeException: Handler{xxxx} sending message to a Handler on a dead thread"。
通常性的,若是是你实现本身的Looper和Handler,建议在Looper.prepare()后,调用Looper.myLooper()来获取对这个线程Looper的引用。
用途:0. 能够调用quit()终止服务线程 1. 接收消息时检查消息循环是否已经退出ui
值得一说的是: 线程终止了,有时候并非你本身终止的,极可能能是系统的某个正常的时序致使的(只是你没有注意到这个次序,而后写代码的时候没有注意)this
上面已经说清楚了,下面是详细信息&啰嗦分界线(下面再多说也就这么回事儿,别往下看了,下面就说一个简单的案例)spa
案例:(使用 IntentService 的发送短信,代码以下)线程
在IntentService内部实际是开启的一个工做线程。
@Override protected void onHandleIntent(Intent intent) { Bundle data = intent.getExtras(); String[] recipients = null; String message = getString(R.string.unknown_event); String name = getString(R.string.app_name); if (data != null && data.containsKey(Constants.Services.RECIPIENTS)) { recipients = data.getStringArray(Constants.Services.RECIPIENTS); name = data.getString(Constants.Services.NAME); message = data.getString(Constants.Services.MESSAGE); for (int i = 0; i < recipients.length; i++) { if(!StringUtils.isNullOrEmpty(recipients[i])) { try { Intent sendIntent = new Intent(this, SMSReceiver.class); sendIntent.setAction(Constants.SMS.SEND_ACTION); PendingIntent sendPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, sendIntent, PendingIntent.FLAG_UPDATE_CURRENT); Intent deliveryIntent = new Intent(this, SMSReceiver.class); deliveryIntent.setAction(Constants.SMS.DELIVERED_ACTION); PendingIntent deliveryPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, deliveryIntent, PendingIntent.FLAG_UPDATE_CURRENT); SmsManager.getDefault().sendTextMessage(recipients[i].trim(), null, "[" + name + "] " + message, sendPendingIntent, deliveryPendingIntent); } catch (Exception e) { Log.e(TAG, "sendTextMessage", e); e.printStackTrace(); Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); MainActivity.instance.writeToLogFile(e.getMessage(), System.currentTimeMillis()); } } } } }
(明眼人一看就知道,那个catch语句写的有问题)
catch (Exception e) { Log.e(TAG, "sendTextMessage", e); e.printStackTrace(); Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); MainActivity.instance.writeToLogFile(e.getMessage(), System.currentTimeMillis()); }
结果就报错了:
Google了一下资料,网址上是这么说的:
(大意翻译: 缘由是你在一个由intentService控制生命周期的线程种建立了toast,手机先会显示这个toast,以后仍是用这个线程的handler去隐藏&关闭这个toast;可是当onHandleIntent结束的时候,这个线程就挂了,而后绑定在这个线程上的handler也就不存在了,完事儿这个toast就关闭不了了,怎么办呢?发给主线程吧,它的toast的Handeler还存活,能够隐藏toast)
解决方案呢?(简单,粗暴)
为何会向一个死线程发消息呢?
由于onHandleIntent(Intent intent)结束了这个线程也就没有了,到底怎么回事儿?
handler没有了,因此cannot hide toast?
若是我没有记错的话,这个toast的生命周期应该是NotificationManagerService控制的吧?
(IntentService源码剖析)----TODO
(Toast生命周期源码剖析)----TODO