縮略信息是: sending message to a Handler on a dead thread 我是用IntentService時報的


稍微纖細一點兒的信息是: Handler (android.os.Handler) {215ddea8} sending message to a Handler on a dead thread。

在另一次在IntentService里使用MediaPlayer 播放鈴聲也再現錯誤,信息是:Handler) {42414500} sending message to a Handler on a dead thread。

本次的完整信息是:

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之類的,已經被你們說爛了。

 

我就簡單概括一句(當然下面也有很詳細的)

一旦一個線程的消息循環退出后,不能再給其發送消息,否則會有RuntimeException拋出。
就是你一般性看到的:

"RuntimeException: Handler{xxxx} sending message to a Handler on a dead thread"。

一般性的,如果是你實現自己的Looper和Handler,建議在Looper.prepare()后,調用Looper.myLooper()來獲取對這個線程Looper的引用。
用途:0. 可以調用quit()終止服務線程   1. 接收消息時檢查消息循環是否已經退出

 

值得一說的是: 線程終止了,有時候並不是你自己終止的,很可能能是系統的某個正常的時序導致的(只是你沒有注意到這個次序,然后寫代碼的時候沒有注意)


 

上面已經說清楚了,下面是詳細信息&啰嗦分界線(下面再多說也就這么回事兒,別往下看了,下面就說一個簡單的案例)

 

案例:(使用 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM