以下例外意味着什么;我该如何解决?
这是代码:
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)
答案 0 :(得分:793)
您需要从UI线程中调用Toast.makeText(...)
:
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
}
});
这是从another (duplicate) SO answer复制粘贴的。
答案 1 :(得分:623)
你是从工作线程调用的。您需要从主线程中调用Toast.makeText()
(以及处理UI的大多数其他函数)。例如,您可以使用处理程序。
在文档中查找Communicating with the UI Thread。简而言之:
// Set this up in the UI thread.
mHandler = new Handler(Looper.getMainLooper()) {
@Override
public 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();
}
其他选项:
您可以使用AsyncTask,这适用于在后台运行的大多数内容。它有一些钩子,你可以调用它来表明进度,以及何时完成。
您也可以使用Activity.runOnUiThread()。
答案 2 :(得分:427)
最好的替代方法是使用RxAndroid
(RxJava
的特定绑定)来P
MVP
来处理数据。
首先从现有方法返回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> () {
@Override
public void onCompleted() {
// Print Toast on completion
}
@Override
public void onError(Throwable e) {}
@Override
public 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();
用于为线程运行消息循环的类。默认情况下的线程 没有与之关联的消息循环;创建一个,打电话 prepare()在运行循环的线程中,然后循环()到 让它处理消息,直到循环停止。
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();
}
}
AsyncTask允许您对用户执行异步工作 接口。它在工作线程中执行阻塞操作 然后在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 work
return null;
}
protected void onPostExecute(Void param) {
//Print Toast or open dialog
}
}
Handler允许您发送和处理Message和Runnable对象 与线程的MessageQueue相关联。
Message msg = new Message();
new Thread()
{
public void run()
{
msg.arg1=1;
handler.sendMessage(msg);
}
}.start();
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
if(msg.arg1==1)
{
//Print Toast or open dialog
}
return false;
}
});
答案 3 :(得分:78)
试试这个,当你看到由于Looper没有在handler之前准备好而导致的runtimeException。
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@override
void run() {
// Run your task here
}
}, 1000 );
答案 4 :(得分:69)
sudo rpi-update f74b92120e0d469fc5c2dc85b2b5718d877e1cbb
sudo reboot
。 Looper.getMainLooper()帮助您实现目标:
pi@raspberrypi:~ $ sudo gatttool -b EC:EA:FA:D8:F9:77 -t random -I
[EC:EA:FA:D8:F9:77][LE]> connect
Attempting to connect to EC:EA:FA:D8:F9:77
Connection successful
[EC:EA:FA:D8:F9:77][LE]> primary
attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0008, end grp handle: 0x000b uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x000c, end grp handle: 0x0011 uuid: 713d0000-503e-4c75-ba94-3148f18d941e
attr handle: 0x0012, end grp handle: 0xffff uuid: 0000180a-0000-1000-8000-00805f9b34fb
此方法的一个优点是您可以在没有Activity(或没有Context)的类中使用它。
答案 5 :(得分:39)
我遇到了同样的问题,这就是我修复它的方法:
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);
}
@Override
public 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:
//TBD
default:
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());
希望这有帮助。
答案 6 :(得分:32)
错误原因:
工作线程用于执行后台任务,除非您调用 runOnUiThread 之类的方法,否则无法在工作线程中的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
。
答案 7 :(得分:21)
我收到此错误,直到我执行了以下操作。
public void somethingHappened(final Context context)
{
Handler handler = new Handler(Looper.getMainLooper());
handler.post(
new Runnable()
{
@Override
public 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() {
@Override
public void run() {
Toast.makeText(ApplicationHolder.INSTANCE.getCustomApplication(), message, Toast.LENGTH_SHORT)
.show();
}
}
);
}
}
答案 8 :(得分:19)
这就是我所做的。
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast(...);
}
});
视觉组件被锁定&#34;来自外部线程的更改。 因此,由于toast在主屏幕上显示由主线程管理的内容,因此您需要在该线程上运行此代码。 希望有所帮助:)
答案 9 :(得分:8)
这是因为Toast.makeText()是从工作线程调用的。它应该从主UI线程调用,如此
runOnUiThread(new Runnable() {
public void run() {
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
}
});
答案 10 :(得分:7)
ChicoBird的答案为我工作。我做的唯一改变是创建了我必须做的UIHandler
HandlerThread uiThread = new HandlerThread("UIHandler");
Eclipse拒绝接受任何其他内容。我想是有道理的。
uiHandler
显然是某个全局定义的类。我仍然没有声称理解Android是如何做到这一点以及发生了什么,但我很高兴它有效。现在我将继续研究它,看看我是否能理解Android正在做什么以及为什么必须经历所有这些环和循环。感谢ChicoBird的帮助。
答案 11 :(得分:6)
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
}
});
答案 12 :(得分:4)
当我的回调尝试显示对话框时,我遇到了同样的问题。
我使用活动中的专用方法解决了它 - 在活动实例成员级别 - 使用runOnUiThread(..)
public void showAuthProgressDialog() {
runOnUiThread(new Runnable() {
@Override
public void run() {
mAuthProgressDialog = DialogUtil.getVisibleProgressDialog(SignInActivity.this, "Loading ...");
}
});
}
public void dismissAuthProgressDialog() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mAuthProgressDialog == null || ! mAuthProgressDialog.isShowing()) {
return;
}
mAuthProgressDialog.dismiss();
}
});
}
答案 13 :(得分:4)
出色的Kotlin解决方案:
runOnUiThread {
// Add your ui thread code here
}
答案 14 :(得分:4)
对于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();
});
}
答案 15 :(得分:3)
首先呼叫Looper.prepare()
,然后再呼叫Toast.makeText().show()
,最后呼叫Looper.loop()
,例如:
Looper.prepare() // to be able to make toast
Toast.makeText(context, "not connected", Toast.LENGTH_LONG).show()
Looper.loop()
答案 16 :(得分:1)
Handler handler2;
HandlerThread handlerThread=new HandlerThread("second_thread");
handlerThread.start();
handler2=new Handler(handlerThread.getLooper());
现在handler2将使用与主线程不同的线程来处理消息。
答案 17 :(得分: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()
...
答案 18 :(得分:1)
使用lambda:
activity.runOnUiThread(() -> Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show());
答案 19 :(得分:0)
我遇到了同样的问题,这就是现在对我来说很好用的 例如,这是我在后台和 ui 线程中执行任务的代码 看看looper是如何使用的
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
// your Background Task here
runOnUiThread(new Runnable() {
@Override
public void run() {
// update your UI here
Looper.loop();
}
});
}
}).start();
我希望这对你或其他人有帮助
答案 20 :(得分: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();
答案 21 :(得分:0)
最近,我遇到了这个问题 - 之所以发生这种情况,是因为我试图调用一个函数,该函数将在构造函数中执行一些 UI 操作。从构造函数中删除初始化为我解决了这个问题。
答案 22 :(得分:0)
协程会完美地完成
CoroutineScope(Job() + Dispatchers.Main).launch {
Toast.makeText(context, "yourmessage",Toast.LENGTH_LONG).show()}
答案 23 :(得分:0)
new Handler(Looper.getMainLooper()).post(() -> {
// Work in the UI thread
};
Handler(Looper.getMainLooper()).post{
// Work in the UI thread
}
GL
答案 24 :(得分: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}
答案 25 :(得分:0)
您需要在UI线程上创建烤面包。在下面找到示例。
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "YOUR_MESSAGE", Toast.LENGTH_SHORT).show();
}
});
有关显示Toast消息的信息,请参阅此article
答案 26 :(得分:0)
我遇到了同样的问题,我只是通过将Toast放在Asynctask <>的onPostExecute()覆盖函数中来解决了它,并且它起作用了。
答案 27 :(得分:0)
当从任何后台线程调用主线程上的某些内容时,通常会发生这种情况。让我们看一个例子,例如。
private class MyTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
textView.setText("Any Text");
return null;
}
}
在上面的示例中,我们在textInview上设置文本,该文本视图位于doInBackground()方法的主UI线程中,该方法仅在工作线程上运行。
答案 28 :(得分:0)
Toast,AlertDialogs 需要在UI线程上运行,你可以使用 Asynctask 在android开发中正确使用它们。但有些情况我们需要自定义超时,所以我们使用线程,但是在线程中我们不能像在AsyncTask中那样使用Toast,Alertdialog。所以我们需要单独的 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秒内睡眠我的线程,之后我想在 mainthread 实现处理程序中显示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 ...希望这会对你有所帮助
答案 29 :(得分:-2)
我使用以下代码显示来自非主线程“context”的消息,
npm i coffee-script
然后使用如下:
npm i coffee-script -g