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

以下异常是什么意思;如何修复它?

这是代码:

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)
947333 次浏览

您正在从工作线程调用它。您需要从主线程中调用Toast.makeText()(以及大多数其他处理UI的函数)。例如,您可以使用处理程序。

在留档中查找与UI线程通信。简而言之:

// Set this up in the UI thread.
mHandler = new Handler(Looper.getMainLooper()) {@Overridepublic void handleMessage(Message message) {// This is where you do your work in the UI thread.// Your worker tells you in the message what to do.}};
void workerThread() {// And this is how you call it from the worker thread:Message message = mHandler.obtainMessage(command, parameter);message.sendToTarget();}

其他选项:

您可以使用#0。如果您有Activity,请直接使用:

@WorkerThreadvoid workerThread() {myActivity.runOnUiThread(() -> {// This is where your UI code goes.}}

你也可以发布到主活套。如果你只有一个Context,这很好。

@WorkerThreadvoid workerThread() {ContextCompat.getMainExecutor(context).execute(()  -> {// This is where your UI code goes.}}

已废弃:

您可以使用异步任务,它适用于在后台运行的大多数事情。它有钩子,您可以调用它来指示进度,以及何时完成。

它很方便,但如果使用不当,可能会泄漏上下文。它已被正式弃用,您不应该再使用它了。

我遇到了同样的问题,这是我如何解决它:

private final class UIHandler extends Handler{public static final int DISPLAY_UI_TOAST = 0;public static final int DISPLAY_UI_DIALOG = 1;
public UIHandler(Looper looper){super(looper);}
@Overridepublic void handleMessage(Message msg){switch(msg.what){case UIHandler.DISPLAY_UI_TOAST:{Context context = getApplicationContext();Toast t = Toast.makeText(context, (String)msg.obj, Toast.LENGTH_LONG);t.show();}case UIHandler.DISPLAY_UI_DIALOG://TBDdefault:break;}}}
protected void handleUIRequest(String message){Message msg = uiHandler.obtainMessage(UIHandler.DISPLAY_UI_TOAST);msg.obj = message;uiHandler.sendMessage(msg);}

要创建UIHandler,您需要执行以下操作:

    HandlerThread uiThread = new HandlerThread("UIHandler");uiThread.start();uiHandler = new UIHandler((HandlerThread) uiThread.getLooper());

希望这有帮助。

ChicoBird的回答对我很有效。我唯一做的改变是创建了UIHandler,我必须这样做

HandlerThread uiThread = new HandlerThread("UIHandler");

Eclipse拒绝接受其他任何东西。我想这是有道理的。

此外,uiHandler显然是在某个地方定义的类全局。我仍然不声称了解Android是如何做到这一点以及发生了什么,但我很高兴它有效。现在我将继续研究它,看看我是否能理解Android在做什么以及为什么必须经历所有这些循环和循环。谢谢chicoBird的帮助。

您需要从UI线程调用Toast.makeText(...)

activity.runOnUiThread(new Runnable() {public void run() {Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();}});

这是从另一个(重复)所以答案复制粘贴的。

错误原因:

辅助线程用于执行后台任务,除非您调用系统运行之类的方法,否则您无法在辅助线程中的UI上显示任何内容。如果您尝试在不调用runOnUiThread的情况下在UI线程上显示任何内容,将会出现java.lang.RuntimeException

因此,如果您在activity中但从工作线程调用Toast.makeText(),请执行以下操作:

runOnUiThread(new Runnable(){public void run(){Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();}});

上面的代码确保您在UI thread中显示Toast消息,因为您在runOnUiThread方法中调用它。所以没有更多的java.lang.RuntimeException

更新-2016

最好的选择是使用RxAndroidRxJava的特定绑定)为MVP中的P负责数据。

首先从现有方法返回Observable

private Observable<PojoObject> getObservableItems() {return Observable.create(subscriber -> {
for (PojoObject pojoObject: pojoObjects) {subscriber.onNext(pojoObject);}subscriber.onCompleted();});}

像这样使用这个Observable-

getObservableItems().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<PojoObject> () {@Overridepublic void onCompleted() {// Print Toast on completion}
@Overridepublic void onError(Throwable e) {}
@Overridepublic void onNext(PojoObject pojoObject) {// Show Progress}});}

----------------------------------------------------------------------------------------------------------------------------------

我知道我来晚了一点,但我要走了。Android基本上适用于两种线程类型,即UI线程后台线程。根据android留档-

不要从UI线程外部访问Android UI工具包来解决此问题,Android提供了几种从其他线程访问UI线程的方法。以下是可以提供帮助的方法列表:

Activity.runOnUiThread(Runnable)View.post(Runnable)View.postDelayed(Runnable, long)

现在有各种方法来解决这个问题。

我将通过代码示例解释它:

系统运行

new Thread(){public void run(){myactivity.this.runOnUiThread(new Runnable(){public void run(){//Do your UI operations like dialog opening or Toast here}});}}.start();

套环

用于为线程运行消息循环的类。线程默认执行没有与它们关联的消息循环;要创建一个,请调用在要运行循环的线程中准备(),然后循环()到让它处理消息,直到循环停止。

class LooperThread extends Thread {public Handler mHandler;
public void run() {Looper.prepare();
mHandler = new Handler() {public void handleMessage(Message msg) {// process incoming messages here}};
Looper.loop();}}

异步任务

允许您对用户执行异步工作接口。它在工作线程中执行阻塞操作并然后在UI线程上发布结果,而无需您自己处理线程和/或处理程序。

public void onClick(View v) {new CustomTask().execute((Void[])null);}

private class CustomTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... param) {//Do some workreturn null;}
protected void onPostExecute(Void param) {//Print Toast or open dialog}}

处理程序

处理程序允许您发送和处理消息和可运行对象与线程的消息队列关联。

Message msg = new Message();

new Thread(){public void run(){msg.arg1=1;handler.sendMessage(msg);}}.start();


Handler handler = new Handler(new Handler.Callback() {
@Overridepublic boolean handleMessage(Message msg) {if(msg.arg1==1){//Print Toast or open dialog}return false;}});

试试这个,当你看到runtimeException由于循环未在处理程序之前准备。

Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {@Overridepublic void run() {// Run your task here}}, 1000 );

我犯了这个错误,直到我做了以下事情。

public void somethingHappened(final Context context){Handler handler = new Handler(Looper.getMainLooper());handler.post(new Runnable(){@Overridepublic void run(){Toast.makeText(context, "Something happened.", Toast.LENGTH_SHORT).show();}});}

并把它变成一个单例类:

public enum Toaster {INSTANCE;
private final Handler handler = new Handler(Looper.getMainLooper());
public void postMessage(final String message) {handler.post(new Runnable() {@Overridepublic void run() {Toast.makeText(ApplicationHolder.INSTANCE.getCustomApplication(), message, Toast.LENGTH_SHORT).show();}});}
}

Toast.makeText()只能从Main/UI线程调用。Looper.getMainLooper()帮助您实现它:

java

new Handler(Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() {// write your code here}});

科特林

Handler(Looper.getMainLooper()).post {// write your code here}

此方法的一个优点是您可以在没有活动或上下文的情况下运行UI代码。

这是因为Toast.makeText()是从工作线程调用的。它应该像这样从主UI线程调用

runOnUiThread(new Runnable() {public void run() {Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);}});

吐司,警报对话框需要在UI线程上运行,你可以使用异步任务在android中正确使用它们development.but在某些情况下我们需要自定义超时,所以我们使用线程,但在线程中我们不能使用Toast,Alert对话框,就像我们在AsyncTask中使用的那样。

public void onSigned() {Thread thread = new Thread(){@Overridepublic 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 = 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…希望这能帮助你

要在线程中显示对话框或烤面包机,最简洁的方法是使用活动对象。

例如:

new Thread(new Runnable() {@Overridepublic 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()...

当我的回调试图显示一个对话框时,我遇到了同样的问题。

我用活动中的专用方法解决了它-在活动实例成员级别-使用runOnUiThread(..)

public void showAuthProgressDialog() {runOnUiThread(new Runnable() {@Overridepublic void run() {mAuthProgressDialog = DialogUtil.getVisibleProgressDialog(SignInActivity.this, "Loading ...");}});}
public void dismissAuthProgressDialog() {runOnUiThread(new Runnable() {@Overridepublic void run() {if (mAuthProgressDialog == null || ! mAuthProgressDialog.isShowing()) {return;}mAuthProgressDialog.dismiss();}});}

我就是这么做的。

new Handler(Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() {Toast(...);}});

可视组件被“锁定”到来自外部线程的更改。因此,由于吐司在主屏幕上显示了由主线程管理的内容,因此您需要在该线程上运行此代码。希望有帮助:)

对于Rxjava和RxAndroid用户:

public static void shortToast(String msg) {Observable.just(msg).observeOn(AndroidSchedulers.mainThread()).subscribe(message -> {Toast.makeText(App.getInstance(), message, Toast.LENGTH_SHORT).show();});}

我使用以下代码显示来自非主线程“上下文”的消息,

@FunctionalInterfacepublic interface IShowMessage {Context getContext();
default void showMessage(String message) {final Thread mThread = new Thread() {@Overridepublic 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!");@Overridepublic Context getContext() {return getApplicationContext();}}

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

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

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

在上面的示例中,我们在doIn背景()方法的主UI线程中的文本视图上设置文本,该方法仅在工作线程上运行。

 runOnUiThread(new Runnable() {public void run() {Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();}});

我遇到了同样的问题,我简单地通过将Toast放在Async任务<>的onPostExecute()覆盖函数中来修复它,它起作用了。

Handler handler2;HandlerThread handlerThread=new HandlerThread("second_thread");handlerThread.start();handler2=new Handler(handlerThread.getLooper());

现在handler2将使用与主线程不同的线程来处理消息。

精彩的静态编程语言解决方案:

runOnUiThread {// Add your ui thread code here}

首先呼叫Looper.prepare(),然后呼叫Toast.makeText().show()最后呼叫Looper.loop(),例如:

Looper.prepare() // to be able to make toastToast.makeText(context, "not connected", Toast.LENGTH_LONG).show()Looper.loop()

您需要在UI线程上创建吐司。找到下面的示例。

runOnUiThread(new Runnable() {public void run() {Toast.makeText(activity, "YOUR_MESSAGE", Toast.LENGTH_SHORT).show();}});

要显示Toast消息,请参阅此文章

以下是使用协程的静态编程语言的解决方案:

通过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}

使用lambda:

activity.runOnUiThread(() -> Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show());

Java8

new Handler(Looper.getMainLooper()).post(() -> {// Work in the UI thread
});

静态编程语言

Handler(Looper.getMainLooper()).post{// Work in the UI thread}

GL

协程会做得很好

CoroutineScope(Job() + Dispatchers.Main).launch {Toast.makeText(context, "yourmessage",Toast.LENGTH_LONG).show()}

在线程外创建处理程序

final Handler handler = new Handler();
new Thread(new Runnable() {@Overridepublic void run() {try{handler.post(new Runnable() {@Overridepublic void run() {showAlertDialog(p.getProviderName(), Token, p.getProviderId(), Amount);}});
}}catch (Exception e){Log.d("ProvidersNullExp", e.getMessage());}}}).start();

我遇到了同样的问题,现在这段代码对我来说运行良好。
作为一个例子,这是我在后台和UI线程中执行任务的代码。
看看如何使用活套:

new Thread(new Runnable() {@Overridepublic void run() {Looper.prepare();                                
// your Background Task here
runOnUiThread(new Runnable() {@Overridepublic void run() {
// update your UI here                                
Looper.loop();}});}}).start();

最近,我遇到了这个问题——它的发生是因为我试图从构造函数中调用一个要做一些UI事情的函数。从构造函数中删除初始化为我解决了这个问题。