I am working on a background service that for a period of time poll to a server something. The point is that: I have an IntentService (called NotificationsService) which calls another service, but the response of this request does'nt get back. And in the logcat appears:
06-19 05:12:00.151: W/MessageQueue(6436): Handler (android.os.Handler) {416659f0} sending message to a Handler on a dead thread
06-19 05:12:00.151: W/MessageQueue(6436): java.lang.RuntimeException: Handler (android.os.Handler) {416659f0} sending message to a Handler on a dead thread
06-19 05:12:00.151: W/MessageQueue(6436): at android.os.MessageQueue.enqueueMessage(MessageQueue.java:196)
06-19 05:12:00.151: W/MessageQueue(6436): at android.os.Handler.sendMessageAtTime(Handler.java:473)
06-19 05:12:00.151: W/MessageQueue(6436): at android.os.Handler.sendMessageDelayed(Handler.java:446)
06-19 05:12:00.151: W/MessageQueue(6436): at android.os.Handler.post(Handler.java:263)
06-19 05:12:00.151: W/MessageQueue(6436): at android.os.ResultReceiver$MyResultReceiver.send(ResultReceiver.java:50)
I looked here problems similar but I got confused (I'm not using any AsyncTask, and I've looked for CommonsWare code wakefullIntent but i didn't understand it).
Here it's the code for NotificationsService.java
public class NotificationsService extends IntentService {
private static int TIME_INTERVAL_MILIS=90000;
private static final int REFRESH=10;
private NotificationManager noteManager;
private static List<FlightStatusNote> flights= new ArrayList<FlightStatusNote>();
public NotificationsService(){
super("NotificationsService");
}
@Override
public void onCreate(){
Log.d("notificationsSservice","onCreate");
super.onCreate();
noteManager=(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d("NotificationsService","Me llamaron");
Log.d("NotificationsService", "intervalo:"+NotificationsService.TIME_INTERVAL_MILIS);
Log.d("NotificationsService","Itero por cada vuelo registrado para notificar");
for(FlightStatusNote f: flights){
FlightStatus fly=f.getFlight();
Log.d("NotificationsService","Vuelo id:"+fly.getAirlineId()+fly.getNumberFlight());
Intent intentaux=new Intent(Intent.ACTION_SYNC,null,getBaseContext(),FlightStatusService.class);
intentaux.putExtra("airlineFlight", fly.getAirlineId());
intentaux.putExtra("numberFlight",fly.getNumberFlight() );
intentaux.putExtra("receiver", new ResultReceiver(new Handler()) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
Log.d("notificationsService","response received");
if (resultCode == FlightStatusService.STATUS_OK) {
List<FlightStatus> fly = (List<FlightStatus>)resultData.getSerializable("return");
for(FlightStatus f: fly){
int indexNote=flights.indexOf(new FlightStatusNote(f,null));
FlightStatusNote fsNote=flights.get(indexNote);
List<String> changes=fsNote.hasChanged(f);
if(changes==null){
Log.d("notificationsService","changes is null");
}
else{
Log.d("notficationsService", "comething changed");
createNotification(f, changes);
}
}
}
}
});
startService(intentaux);
}
AlarmManager alarmMgr = (AlarmManager) getBaseContext().getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getBaseContext(), 0, new Intent(getBaseContext(), DealAlarmReceiver.class), 0);
alarmMgr.set(AlarmManager.RTC, System.currentTimeMillis()+NotificationsService.TIME_INTERVAL_MILIS, pendingIntent);
}
}
If anyone can help me, I would appreciate it a lot! Cheers!
Edit: I think the problem is that the Log "response received" it doesn't appear.
IntentService
s create a new thread when you call the onHandleIntent
method, and then kills that thread as soon as that onHandleIntent
method returns.
You need to create your listener somewhere else, IntentService
s aren't safe for setting up listeners because they die. They're mainly used for executing a short task outside of the main thread. See a similar question here.
Edit: Also see documentation on IntentService.
Each Handler
has a Looper
, and a Looper
is associated with a Thread
(usually a HandlerThread
). The general problem is when a Handler
becomes associated with thread that stops running. If someone tries to use the Handler
, it will fail with the message "sending message to a Handler on a dead thread".
If you just do new Handler()
it becomes associated with the current thread (rather, it becomes associated with the Looper
associated w/ the current thread). If you do this on a thread that that stops (such as the worker thread for an IntentService
) you'll have the issue. The problem of course isn't limited to this root cause, it can happen in any number of ways.
Any easy fix is to construct your Handler
like,
Handler h = new Handler(Looper.getMainLooper());
This associates the Handler
with the main looper, or the main application thread which will never die (good for things like callbacks, but not for any blocking work obviously). Another more complex fix is to create a dedicated thread for the Handler
,
HandlerThread ht = new HandlerThread(getClass().getName());
ht.start();
Handler handler = new Handler(ht.getLooper());
Note that you need to explicitly quit()
the HandlerThread
when you are done with the associated Handler
.
I cannot reply back because I'm new, but basically what 'jpalm' mentioned is the most accurate answer.
Basically there is a thing that I understood playing with ServiceIntent: they will die inmediately they finish. Meaning that if you submit a work in the framework (like starting an Activity); the Framework could immediately go back to you to tell you 'startService(intentaux)' returned OK or whatever (I'm not an expert, I'm new on this too:P ), because it found that your thread is dead already!!!.
When you start your Activity,If you intentionally force your thread be somehow alive until you get the response, this errors doesn't happen.
See http://developer.android.com/guide/components/services.html. Modify the example to not wait, then Toast start crashing sending clear messages like this, even when you believe you are not using ASYNC Method.
07-24 08:03:16.309: W/MessageQueue(1937): java.lang.RuntimeException: Handler (android.os.Handler) {b1016d80} sending message to a Handler on a dead thread
07-24 08:03:16.309: W/MessageQueue(1937): at android.os.MessageQueue.enqueueMessage(MessageQueue.java:320)
07-24 08:03:16.309: W/MessageQueue(1937): at android.os.Handler.enqueueMessage(Handler.java:626)
07-24 08:03:16.309: W/MessageQueue(1937): at android.os.Handler.sendMessageAtTime(Handler.java:595)
07-24 08:03:16.309: W/MessageQueue(1937): at android.os.Handler.sendMessageDelayed(Handler.java:566)
07-24 08:03:16.309: W/MessageQueue(1937): at android.os.Handler.post(Handler.java:326)
07-24 08:03:16.309: W/MessageQueue(1937): at android.widget.Toast$TN.hide(Toast.java:370)
07-24 08:03:16.309: W/MessageQueue(1937): at android.app.ITransientNotification$Stub.onTransact(ITransientNotification.java:55)
07-24 08:03:16.309: W/MessageQueue(1937): at android.os.Binder.execTransact(Binder.java:404)
07-24 08:03:16.309: W/MessageQueue(1937): at dalvik.system.NativeStart.run(Native Method)
I have to say the documentation of android.developers is pretty good but very concise (ULTRA ZIP), meaning that you will have to read and read, word by word, and then when you look into a dictionary after being desperated... you say: IT WAS ALWAYS HERE! :O
it is like a Bible, but for developers :) and somehow we are becoming Android prophets :P
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With