Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sending message to a handler on a dead thread

Tags:

android

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.

like image 227
Mitodina Avatar asked Jun 21 '13 14:06

Mitodina


3 Answers

IntentServices 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, IntentServices 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.

like image 180
jpalm Avatar answered Sep 21 '22 16:09

jpalm


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.

like image 30
Jeffrey Blattman Avatar answered Sep 25 '22 16:09

Jeffrey Blattman


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

like image 5
leandr0garcia Avatar answered Sep 22 '22 16:09

leandr0garcia