无法在未调用Looper.prepare()的线程中创建处理程序

1211
以下异常的意思是什么?我该如何修复它?
这是代码:
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);

这是异常情况:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
     at android.os.Handler.<init>(Handler.java:121)
     at android.widget.Toast.<init>(Toast.java:68)
     at android.widget.Toast.makeText(Toast.java:231)

13
请检查这个库 compile 'com.shamanland:xdroid-toaster:0.0.5',它不需要 runOnUiThread()Context 变量,所有例行程序都已消失!只需调用 Toaster.toast(R.string.my_msg); 就可以了。这里有一个示例:https://github.com/shamanland/xdroid-toaster-example - Oleksii K.
181
多么愚蠢的错误消息!它本可以简单明了,比如"不能在非UI线程中调用此函数,就像当视图从非UI线程被触摸时一样。" - Dheeraj Bhaskar
19
对于那些在不同代码中遇到相同异常消息的人:该异常消息的意思是您正在通过未准备好Looper的线程调用代码。通常这意味着您没有从UI线程调用它,但是您应该这样做(在OP的情况下)-普通线程不会准备Looper,但UI线程总是会准备。 - Helin Wang
1
@OleksiiKropachov,你提到的库的实现方式与执行runOnUiThread()非常相似。 - Helin Wang
1
是的,但它是一个非常有用的封装。 - Oleksii K.
@DheerajBhaskar 我不会轻易评判一个专业开发者的决定,当你不了解这个异常还包含其他情况时,这样做是愚蠢的。对我来说,我遇到了与UI线程无关的相同异常,谷歌自己提供的用于应用内购买的IABHandler,在没有调用Looper.getMainLooper()的情况下使用了新的Handler,出于一些“愚蠢”的原因;当我正常使用它时没有任何问题,但当我在Executors线程池中使用它时,就会出现相同的异常,从未在其中使用任何与UI相关的方法。 - Alireza Jamali
30个回答

1
要在线程中显示对话框或弹出提示,最简洁的方法是使用Activity对象。
例如:
new Thread(new Runnable() {
    @Override
    public void run() {
        myActivity.runOnUiThread(new Runnable() {
            public void run() {
                myActivity.this.processingWaitDialog = new ProgressDialog(myActivity.this.getContext());
                myActivity.this.processingWaitDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
                myActivity.this.processingWaitDialog.setMessage("abc");
                myActivity.this.processingWaitDialog.setIndeterminate(true);
                myActivity.this.processingWaitDialog.show();
            }
        });
        expenseClassify.serverPost(
                new AsyncOperationCallback() {
                    public void operationCompleted(Object sender) {
                        myActivity.runOnUiThread(new Runnable() {
                            public void run() {
                                if (myActivity.this.processingWaitDialog != null 
                                        && myActivity.this.processingWaitDialog.isShowing()) {
                                    myActivity.this.processingWaitDialog.dismiss();
                                    myActivity.this.processingWaitDialog = null;
                                }
                            }
                        }); // .runOnUiThread(new Runnable()
...

1
使用 lambda 表达式:
activity.runOnUiThread(() -> Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show());

0

通常情况下,当任何后台线程调用主线程上的某些内容时,就会发生这种情况。让我们举个例子。

private class MyTask extends AsyncTask<Void, Void, Void> {


@Override
protected Void doInBackground(Void... voids) {
        textView.setText("Any Text");
        return null;
    }
}

在上面的例子中,我们正在从doInBackground()方法中的工作线程设置文本到主UI线程中的textview。

0

Toast,AlertDialogs 需要在 UI 线程上运行,您可以使用 Asynctask 在 Android 开发中正确地使用它们。但是有些情况下我们需要自定义超时时间,因此我们使用线程,但是在线程中我们不能像在 AsyncTask 中那样使用 Toast、Alertdialogs。因此,我们需要单独的Handler 来弹出这些内容。

public void onSigned() {
    Thread thread = new Thread(){
        @Override
        public void run() {
            try{
                sleep(3000);
                Message message = new Message();
                message.what = 2;
                handler.sendMessage(message);
            } catch (Exception e){
                e.printStackTrace();
            }
        }
    };
    thread.start();
}

在上面的例子中,我想让我的线程睡眠3秒钟,然后显示一个Toast消息,在你的主线程中实现handler即可。
handler = new Handler() {
       public void handleMessage(Message msg) {
           switch(msg.what){
              case 1:
              Toast.makeText(getActivity(),"cool",Toast.LENGTH_SHORT).show();
              break;
           }
           super.handleMessage(msg);
       }
};

我在这里使用了switch case,因为如果您需要以相同的方式显示不同的消息,则可以在Handler类中使用switch case...希望这能帮到您。


0
最近我遇到了这个问题 - 这是因为我试图从构造函数中调用一个处理UI的函数。将初始化操作从构造函数中移除解决了我的问题。

0

我曾经遇到过同样的问题,但是我通过将Toast放置在Asynctask<>的onPostExecute()覆盖函数中来解决它,这很简单并且有效。


0

在线程之外创建处理程序

final Handler handler = new Handler();

        new Thread(new Runnable() {
            @Override
            public void run() {
            try{
                 handler.post(new Runnable() {
                        @Override
                        public void run() {
                            showAlertDialog(p.getProviderName(), Token, p.getProviderId(), Amount);
                        }
                    });

                }
            }
            catch (Exception e){
                Log.d("ProvidersNullExp", e.getMessage());
            }
        }
    }).start();

0

这是使用协程的 Kotlin 解决方案:

通过 MainScope() 将您的类扩展为 CoroutineScope:

class BootstrapActivity :  CoroutineScope by MainScope() {}

然后只需这样做:

launch {
        // whatever you want to do in the main thread
    }

不要忘记添加协程的依赖项:

org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}
org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.kotlinCoroutines}

或者简单地使用 launch(Dispatchers.Main) { ... } - CoolMind

0
您需要在UI线程上创建Toast。请参考以下示例。
runOnUiThread(new Runnable() {
  public void run() {
    Toast.makeText(activity, "YOUR_MESSAGE", Toast.LENGTH_SHORT).show();
  }
});

如需显示 Toast 消息,请参考此文章


-2
我使用以下代码从非主线程“context”显示消息:
@FunctionalInterface
public interface IShowMessage {
    Context getContext();

    default void showMessage(String message) {
        final Thread mThread = new Thread() {
            @Override
            public void run() {
                try {
                    Looper.prepare();
                    Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
                    Looper.loop();
                } catch (Exception error) {
                    error.printStackTrace();
                    Log.e("IShowMessage", error.getMessage());
                }
            }
        };
        mThread.start();
    }
}

然后按照以下方式使用:

class myClass implements IShowMessage{

  showMessage("your message!");
 @Override
    public Context getContext() {
        return getApplicationContext();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接