2013-06-21 7 views
18

Sto lavorando su un servizio in background che per un periodo di tempo esegue il polling su un server. Il punto è che: Ho un IntentService (chiamato NotificationsService) che chiama un altro servizio, ma la risposta di questa richiesta non torna indietro. E nel logcat appare:invio di un messaggio a un gestore su un thread morto

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) 

ho guardato qui problemi simili, ma io sono confuso (non sto utilizzando qualsiasi AsyncTask, e ho guardato il codice CommonsWare wakefullIntent ma non ho capito bene).

qui è il codice per 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); 

} 
} 

Se qualcuno mi può aiutare, lo apprezzerei molto! Cheers!

Modifica: Penso che il problema sia che il registro "risposta ricevuta" non appare.

risposta

24

IntentService s creare un nuovo thread quando si chiama il metodo onHandleIntent e quindi elimina il thread non appena viene restituito il metodo onHandleIntent.

È necessario creare l'ascoltatore da qualche altra parte, IntentService s non sono sicuri per la configurazione degli ascoltatori perché muoiono. Sono principalmente utilizzati per eseguire una breve attività al di fuori del thread principale. Vedi una domanda simile here.

Modifica: vedere anche la documentazione su IntentService.

+3

Ho già letto quella domanda simile ma sono ancora bloccato. Dove altro dovrei creare l'ascoltatore? – Mitodina

0

un'occhiata qui

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

        } 


       } 

      } 

si registra un oggetto gestore annonimously definito - perché non legare l'oggetto gestore di un'attività (processo) e vedere se il codice si rompe allora? Essenzialmente, passando una variabile di gestore invece di un nuovo oggetto gestore.

in questo modo, tutti i ResultReceivers utilizzeranno lo stesso oggetto Gestore invece di uno privato.

3

Non riesco a rispondere perché sono nuovo, ma fondamentalmente ciò che "jpalm" menzionato è la risposta più accurata.

Fondamentalmente c'è una cosa che ho capito giocando con ServiceIntent: moriranno subito finiranno. Ciò significa che se si invia un lavoro nel framework (come l'avvio di un'attività); il Framework potrebbe tornare immediatamente da te per dirti 'startService (intentaux)' restituito OK o qualsiasi altra cosa (non sono un esperto, sono nuovo anche su questo: P), perché ha scoperto che il tuo thread è già morto! !!.

Quando si avvia l'attività, se si forza intenzionalmente il thread essere in qualche modo vivo finché non si ottiene la risposta, questo errore non si verifica.

Vedere http://developer.android.com/guide/components/services.html. Modifica l'esempio per non aspettare, poi Toast inizia a bloccarsi inviando messaggi chiari come questo, anche quando ritieni di non utilizzare il metodo 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) 

Devo dire che la documentazione di android.developers è abbastanza buono, ma molto conciso (ZIP ULTRA), il che significa che si dovrà leggere e leggere, parola per parola, e poi quando si guarda in un dizionario dopo essere stato disperato ... tu dici: ERA SEMPRE QUI!: O

è come una Bibbia, ma per gli sviluppatori :) e in qualche modo stiamo diventando profeti Android: P

0

la ragione principale è che devi inserire un messaggio su una coda che non ha crochet a loop. tuttavia, è possibile utilizzare "getMainLooper()" per passare come parametro al "gestore" che si crea.

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

ed è possibile creare un'istanza di Autohändler come questo:

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

Ogni Handler ha un Looper, ed un Looper ha un HandlerThread. Il problema generale è quando un Handler viene associato al thread che smette di funzionare. Se qualcuno tenta di utilizzare Handler, fallirà con il messaggio "invio di un messaggio a un gestore su un thread morto".

Se si esegue solo new Handler(), questo viene associato al thread corrente (piuttosto, viene associato con il valore Looper associato al thread corrente). Se lo fai su un thread che sta per andare via (come il thread di lavoro per un IntentService) avrai il problema. Il problema, naturalmente, non è limitato a questa causa principale, può avvenire in molti modi.

Qualsiasi soluzione semplice è quello di costruire la vostra Handler come,

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

Questo associa il Handler con il crochet principale, o il principale thread dell'applicazione, che non morirà mai. Un'altra correzione più complesso è quello di creare un thread dedicato per il Handler,

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

Nota che è necessario in modo esplicito il quit()HandlerThread quando si è fatto con l'associato Handler.

Problemi correlati