Toast"在死线程上向处理程序发送消息"

Joh*_*ohn 20 android

我试图通过Toast显示一条简单的消息,并得到一个RunTime Exception"在死线程上向Handler发送消息".尝试显示Toast消息的类扩展了IntentService.该类(C2DMReceiver)实际上来自C2DM的ChromeToPhone示例.这是方法:

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

    }
}
Run Code Online (Sandbox Code Playgroud)

我假设因为类扩展了IntentService,所以可以通过这种方式从这里请求一个简单的Toast消息.这不对吗?

Jon*_*low 28

这是由于Android框架中的AsyncTask中存在错误.AsyncTask.java具有以下代码:

private static final InternalHandler sHandler = new InternalHandler();
Run Code Online (Sandbox Code Playgroud)

它期望在主线程上初始化它,但是这不能保证,因为它将在导致类运行其静态初始化器的任何线程上初始化.我重现了Handler引用工作线程的问题.

导致这种情况发生的常见模式是使用IntentService类.C2DM示例代码执行此操作.

一个简单的解决方法是将以下代码添加到应用程序的onCreate方法:

Class.forName("android.os.AsyncTask");
Run Code Online (Sandbox Code Playgroud)

这将强制在主线程中初始化AsyncTask.我在android bug数据库中提交了一个bug.请参阅http://code.google.com/p/android/issues/detail?id=20915.

  • 我这样做了,它甚至没有帮助.始终在收到c2dm通知时,它会记录相同的异常. (4认同)

小智 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();
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 正如[Jonathan Perlow在他的回答中所述](http://stackoverflow.com/a/7818794/1208581),Android框架中存在一个错误,导致在主线程中未创建的Toast运行在处理程序中,没有附加到主线程.通过在主线程(在构造函数中)创建`mMainThreadHandler`,我们确保Toast在主线程中运行.这样我们就可以解决这个问题. (3认同)

Jör*_*örg 11

从后台完成在主线程中烘焙消息的另一种方法是使用一个小实用程序方法.诀窍是创建一个附加到主线程的looper(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();
            }
       });
    }
}
Run Code Online (Sandbox Code Playgroud)


Nat*_*ann 0

您必须从主线程显示 toast,否则它将不会显示在屏幕上。处理程序从创建它的线程中执行。如果您在 IntentService 的 onCreate 中创建处理程序,那么当您发送消息时,它应该按预期工作。