2010-12-14 17 views
20

Próbuję wyświetlić prostą wiadomość za pośrednictwem Toast i otrzymuję wyjątek RunTime "wysyłanie wiadomości do Handler'a na martwym wątku". Klasa, która próbuje wyświetlić komunikat Toast, rozszerza IntentService. Klasa (C2DMReceiver) faktycznie pochodzi z przykładu ChromeToPhone dla C2DM. Oto sposób:Toast "wysyłanie wiadomości do Handler'a na martwym wątku"

/** 
* Called when a cloud message has been received. 
*/ 
@Override 
public void onMessage(Context context, Intent intent) { 
    Log.i(LOG_TAG, "A message notification has occured with the cloud."); 

     Log.i(LOG_TAG, "Showing toast message of the broadcast..."); 
     Toast toast = Toast.makeText(context, "Some text", Toast.LENGTH_LONG); 
     toast.show(); 

     Log.i(LOG_TAG, "Sending notification of the broadcast..."); 
     LauncherUtils.generateNotification(this, "this is where the text would go.", "Broadcast", intent); 

    } 
} 

Sądziłem, ponieważ klasa rozszerza IntentService, że byłoby to możliwe, aby poprosić o prostą wiadomość Toast stąd w ten sposób. Czy to nie prawda?

Odpowiedz

0

Musisz wyświetlić toast z głównego wątku lub nie wyświetli się on na ekranie. Program obsługi jest wykonywany z wątku, w którym został utworzony. Jeśli utworzysz program obsługi onCreate w intentservice, powinien on działać zgodnie z przeznaczeniem podczas wysyłania wiadomości.

+0

Nie jestem pewien, śledzę, gdyż nie ma bezpośredniego odniesienia do obsługi z obiektu toastowego. Zaimplementowałem metodę onCreate, ale nadal otrzymuję wyjątek martwego wątku. Jaki jest właściwy sposób tworzenia programu obsługi w tej sytuacji? To jest mój onCreate, z chronionym handler'owym handler'em; @Override public void onCreate() { super.onCreate(); handler = new Handler() { @Override public void handleMessage (MSG Message) { Log.i (LOG_TAG "W handleMessage ..."); } }; } – John

28

Jest to spowodowane błędem w AsyncTask w systemie Android. AsyncTask.java ma następujący kod:

private static final InternalHandler sHandler = new InternalHandler(); 

spodziewa to być inicjowane w głównym wątku, ale to nie jest gwarantowane, ponieważ zostanie on zainicjowany na dowolny wątek dzieje się spowodować, aby uruchomić swoje klasy statyczne inicjatorów. Powieliłem ten problem, gdy Handler odwołuje się do wątku roboczego.

Typowym wzorcem, który to powoduje, jest użycie klasy IntentService. Kod przykładowy C2DM to robi.

Prostym rozwiązaniem jest dodatek następujący kod metody onCreate aplikacji:

Class.forName("android.os.AsyncTask"); 

wymusi AsyncTask być inicjowane w głównym wątku. Złożyłem błąd w tym w bazie danych błędów Androida. Zobacz http://code.google.com/p/android/issues/detail?id=20915.

+0

Dziękuję bardzo, właśnie zauważyłem, że dzieje się to przypadkowo, a twoja poprawka rozwiązała problem! –

+4

Zrobiłem to i to nie pomogło ani trochę. Zawsze, gdy otrzyma powiadomienie c2dm, loguje ten sam wyjątek. – Ixx

+0

Nie działa również dla mnie. – easycheese

24
public class NetworkService extends IntentService { 
    Handler mMainThreadHandler = null; 

    public NetworkService() { 
     super(NetworkService.class.getName()); 

     mMainThreadHandler = new Handler(); 
    } 

    @Override 
    protected void onHandleIntent(Intent arg) { 
     System.out.printf("Network service intent handling: %s\n", arg.toString()); 
     mMainThreadHandler.post(new Runnable() { 
      @Override 
      public void run() { 
       Toast.makeText(getApplicationContext(), "BusyBox updated", Toast.LENGTH_LONG).show(); 
      } 
     }); 
    } 
} 
+0

[To działa dla mnie] Czy ktoś może wyjaśnić, co się tutaj dzieje i dlaczego to zadziałało? –

+3

Jak [Jonathan Perlow stwierdził w swojej odpowiedzi] (http://stackoverflow.com/a/7818794/1208581), istnieje błąd w Androidzie, który powoduje, że toast, który nie jest tworzony w głównym wątku, uruchomić w programie obsługi, który nie jest podłączony do głównego wątku. Tworząc 'mMainThreadHandler' na głównym wątku (w konstruktorze), upewniamy się, że toast działa w głównym wątku. W ten sposób obejdziemy błąd. – sulai

0

Metoda onMessage nie została wywołana w głównym wątku.

Musisz więc stworzyć nowego Handler'a.

Zastosuj ten kod:

public class GCMIntentService extends GCMBaseIntentService 
{ 
    Handler handler; 
    public GCMIntentService() 
    { 
     handler = new Handler(); 
    } 
} 
9

Inną drogą do osiągnięcia opiekania wiadomości w wątku głównego od tła jest użycie małego metody użytkowego dla tego produktu. Sztuką jest stworzenie programu obsługi podłączonego do looper głównego wątku (Looper.getMainLooper()).

public class ToastUtils { 

    public static void showToastInUiThread(final Context ctx, 
     final int stringRes) { 

     Handler mainThread = new Handler(Looper.getMainLooper()); 
     mainThread.post(new Runnable() { 
      @Override 
      public void run() { 
       Toast.makeText(ctx, ctx.getString(stringRes), Toast.LENGTH_SHORT).show(); 
      } 
     }); 
    } 
} 
+0

Bardzo przydatna wskazówka. Działa jak marzenie –

0

Można uruchomić kod na wątków UI tak:

runOnUiThread(new Runnable() { 
    public void run() { 
    try { 
    //YOUR CODE 
    } catch (Exception e) { 
    Log.d(TAG, e.getMessage()); 
    } 
} 
}); 

To powinno zadziałać

Powiązane problemy