2010-12-14 5 views
20

Я пытаюсь показать простое сообщение через Toast, и получаю исключение RunTime «отправка сообщения обработчику по мертвому потоку». Класс, который пытается показать сообщение Toast, расширяет IntentService. Класс (C2DMReceiver) фактически исходит из примера ChromeToPhone для C2DM. Вот метод:Toast «отправка сообщения обработчику по мертвой теме»

/** 
* 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); 

    } 
} 

Я предполагал, так как класс расширяет IntentService, что можно было бы запросить простое сообщение Toast здесь таким образом. Разве это не так?

ответ

0

Вы должны показать тост из основного потока или не отобразиться на экране. Обработчик выполняется из потока, в котором он был создан. Если вы создаете обработчик в onCreate вашего intenservice, он должен работать так, как было запланировано, когда вы отправляете свое сообщение.

+0

Я не уверен, я следую, так как нет прямой ссылки на обработчик от тоста. Я реализовал метод onCreate, но все равно получаю исключение в виде мертвой нити. Каков правильный способ создания обработчика в этой ситуации? Это мой onCreate, с защищенным обработчиком Handler; @Override общественный void onCreate() { супер.OnCreate(); обработчик = новый Handler() { @Override общественного недействительными handleMessage (сообщ Message) { Log.i (LOG_TAG, "В handleMessage ..."); } }; } – John

28

Это связано с ошибкой в ​​AsyncTask в каркасе Android. AsyncTask.java имеет следующий код:

private static final InternalHandler sHandler = new InternalHandler(); 

Он ожидает, что это будет инициализирован в основном потоке, но не гарантируется, так как он будет инициализирован на какой нить случается, чтобы вызвать класс запустить его статические инициализаторы. Я воспроизвел эту проблему, когда обработчик ссылается на рабочий поток.

Общим примером, который вызывает это, является использование класса IntentService. Код примера C2DM делает это.

Простое решение заключается в добавлении следующего кода в OnCreate метод приложения:

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

Это заставит AsyncTask быть инициализированы в основном потоке. Я зарегистрировал ошибку об этом в базе данных ошибок Android. См. http://code.google.com/p/android/issues/detail?id=20915.

+0

Большое спасибо, просто заметили это случайным образом, и ваше решение решило проблему! –

+4

Я сделал это, и это не помогло даже немного. Всегда, когда он получил уведомление c2dm, он регистрирует одно и то же исключение. – Ixx

+0

Не работал и для меня. – 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

[Это работает для меня] Кто-нибудь может объяснить, что здесь происходит и почему это сработало? –

+3

Как сказал Джонатан Перлоу в своем ответе (http://stackoverflow.com/a/7818794/1208581), в Android Framework есть ошибка, которая вызывает тост, который не создан в основном потоке, до запускается в обработчике, который не привязан к основному потоку. Создав 'mMainThreadHandler' в основном потоке (в конструкторе), мы убеждаемся, что Toast работает в основном потоке. Таким образом мы работаем над ошибкой. – sulai

0

Метод onMessage не был вызван на главную нить.

Для этого вам необходимо создать новый обработчик.

Применить этот код:

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

Другим способом для выполнения тостов сообщения в главном потоке от фона использовать небольшой служебный метод для этого. Хитрость заключается в создании обработчика, который прикреплен к петлевому механизму основного потока (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

Очень полезный совет. Работает как шарм –

0

Вы можете запустить свой код на поток пользовательского интерфейса, как это:

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

Это должно работать нормально