Отправка сообщения обработчику мертвой нити

Я работаю над фоновым сервисом, который на время времени опроса сервера что-то. Дело в том, что у меня есть IntentService (называемый NotificationsService), который вызывает другую службу, но ответ этого запроса не возвращается. И в логарифме появляется:

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)

Я искал похожие проблемы, но я запутался (я не использую AsyncTask, и я искал код CommonsWare wakefullIntent, но я не понял его).

Вот он код для 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);

}
}

Если кто-то может мне помочь, я был бы очень признателен! Ура!

Изменить: я думаю, проблема в том, что получен ответ "Ответ получен" не отображается.

Ответы

Ответ 1

IntentService создайте новый поток при вызове метода onHandleIntent, а затем уничтожьте этот поток, как только этот метод onHandleIntent вернется.

Вам нужно создать своего слушателя где-то еще, IntentService небезопасны для настройки слушателей, потому что они умирают. Они в основном используются для выполнения короткой задачи вне основного потока. См. Аналогичный вопрос здесь.

Изменить: Также см. документацию по IntentService.

Ответ 2

Каждый Handler имеет Looper, а a Looper имеет HandlerThread. Общая проблема заключается в том, когда a Handler становится связанным с потоком, который перестает работать. Если кто-то попытается использовать Handler, он не сработает с сообщением "отправка сообщения обработчику по мертвому потоку".

Если вы просто выполняете new Handler(), он становится связанным с текущим потоком (скорее, он становится связанным с Looper, связанным с текущим потоком). Если вы сделаете это в потоке, который уйдет (например, рабочий поток для IntentService), у вас возникнет проблема. Проблема, конечно, не ограничивается этой первопричиной, она может произойти любым количеством способов.

Любое легкое исправление заключается в том, чтобы построить ваш Handler как,

Handler h = new Handler(Looper.getMainLooper());

Это связывает Handler с основным петлером или с основным потоком приложения, который никогда не умрет. Еще одним сложным решением является создание выделенного потока для Handler,

HandlerThread ht = new HandlerThread(getClass().getName());
ht.start();
Handler handler = new Handler(ht.getLooper());

Обратите внимание, что вам нужно явно указать quit() HandlerThread, когда вы закончите с помощью Handler.

Ответ 3

Я не могу ответить, потому что я новичок, но в основном то, что упоминалось в jpalm, является наиболее точным ответом.

В основном есть вещь, которую я понял, играя с ServiceIntent: они умрут сразу же, как они закончат. Это означает, что если вы отправляете работу в рамках (например, начиная деятельность); Framework может сразу вернуться к вам, чтобы сообщить вам, что "startService (intentaux)" вернул ОК или что-то еще (я не эксперт, я тоже новичок в этом: P), потому что он обнаружил, что ваш поток уже мертв!!!.

Когда вы начинаете свою деятельность, если вы намеренно заставляете свой поток быть каким-то образом живым до тех пор, пока не получите ответ, таких ошибок не произойдет.

См. http://developer.android.com/guide/components/services.html. Измените пример, чтобы не дождаться, а затем Toast начнет сбой отправки ясных сообщений, подобных этому, даже если вы считаете, что не используете метод ASYNC.

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)

Я должен сказать, что документация для android.developers довольно хороша, но очень кратким (ULTRA ZIP), что означает, что вам придется читать и читать, слово за словом, а затем, когда вы смотрите в словарь после отчаяния... вы говорите: ЭТО ВСЕГДА ЗДЕСЬ!: О

это похоже на Библию, но для разработчиков:) и почему-то мы становимся пророками Android: P

Ответ 4

смотрите здесь

             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);
                        }

                    }


                }

            }

вы публикуете анонимно определенный объект-обработчик - почему бы не связать этот объект-обработчик с действием (процессом) и посмотреть, не сломается ли код? По существу, передача переменной обработчика вместо нового объекта обработчика.

таким образом, все ResultReceivers будут использовать тот же объект Handler вместо частного.

Ответ 5

Основная причина заключается в том, что вы поставили сообщение в очередь, которая не имеет петлирования. однако вы можете использовать "getMainLooper()" для передачи в качестве параметра для созданного "Handler".

public AutoHandler(Context context, Looper looper) {
    super(looper);
    this.context = context;
}

и вы можете создать экземпляр AutoHandler следующим образом:

autoHandler = new AutoHandler(this, getMainLooper());