Android Can';t在未调用Looper.prepare()的线程内创建处理程序
以下例外情况是什么意思;我怎样才能修好它 代码如下:Android Can';t在未调用Looper.prepare()的线程内创建处理程序,android,ui-thread,android-toast,Android,Ui Thread,Android Toast,以下例外情况是什么意思;我怎样才能修好它 代码如下: Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT); 这是一个例外: java.lang.RuntimeException:无法在未调用Looper.prepare()的线程内创建处理程序 android.os.Handler.(Handler.java:121) 在android.widget.Toast.(Toast.java:68) 位于and
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
这是一个例外:
java.lang.RuntimeException:无法在未调用Looper.prepare()的线程内创建处理程序
android.os.Handler.(Handler.java:121)
在android.widget.Toast.(Toast.java:68)
位于android.widget.Toast.makeText(Toast.java:231)
您正在从工作线程调用它。您需要从主线程中调用Toast.makeText()
(以及处理UI的大多数其他函数)。例如,您可以使用处理程序
查阅文档。简言之:
// 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();
}
其他选项:
你可以用。如果您有活动
,则非常简单:
@WorkerThread
void workerThread(){
myActivity.runOnUiThread(()->{
//这就是您的UI代码所在。
}
}
你也可以发布到主循环器。如果你只有一个上下文
,这会非常有效
@WorkerThread
void workerThread(){
ContextCompat.getMainExecutor(context.execute)(()->{
//这就是您的UI代码所在。
}
}
已弃用:
您可以使用一个,它对在后台运行的大多数事情都很有效。它有一些钩子,您可以调用这些钩子来指示进度以及何时完成
它很方便,但如果使用不正确,可能会泄漏上下文。它已被正式弃用,您不应该再使用它了。我遇到了同样的问题,下面是我如何修复它的:
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());
class myClass implements IShowMessage{
showMessage("your message!");
@Override
public Context getContext() {
return getApplicationContext();
}
}
希望这能有所帮助。ChicoBird的回答对我有效。我唯一做的改变是创建了UIHandler,我必须在其中执行操作
HandlerThread uiThread = new HandlerThread("UIHandler");
Eclipse拒绝接受其他任何东西。我想这是有道理的
另外,
uiHandler
显然是一个定义在某个地方的全局类。我仍然不知道安卓是如何做到这一点的,也不知道发生了什么,但我很高兴它能起作用。现在我将继续研究它,看看我是否能理解安卓在做什么,以及为什么要经历所有这些困难和循环。谢谢你的帮助ird.您需要从UI线程调用Toast.makeText(…)
:
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
}
});
这是从粘贴的副本。错误原因: 工作线程用于执行后台任务,除非调用类似runOnUiThread的方法,否则无法在工作线程的UI上显示任何内容。如果尝试在UI线程上显示任何内容而不调用runOnUiThread,则会出现
java.lang.RuntimeException
因此,如果您在一个活动中
但从工作线程调用Toast.makeText()
,请执行以下操作:
runOnUiThread(new Runnable()
{
public void run()
{
Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();
}
});
上面的代码确保您在UI线程中显示Toast消息,因为您在runOnUiThread
方法中调用它。因此不再java.lang.RuntimeException
更新-2016
最好的替代方法是使用RxAndroid
(针对RxJava
的特定绑定)使MVP
中的p
负责数据
首先从您现有的方法返回可观察的
private Observable<PojoObject> getObservableItems() {
return Observable.create(subscriber -> {
for (PojoObject pojoObject: pojoObjects) {
subscriber.onNext(pojoObject);
}
subscriber.onCompleted();
});
}
现在有各种各样的方法来解决这个问题
我将通过代码示例对此进行解释:
runOnUiThread
活套
类用于为线程运行消息循环。默认情况下,线程
没有与之关联的消息循环;要创建一个,请调用
在要运行循环的线程中准备(),然后在
让它处理消息,直到循环停止
异步任务
AsyncTask允许您对用户执行异步工作
接口。它在工作线程和
然后在UI线程上发布结果,而无需
自己处理线程和/或处理程序
当您看到由于在处理程序之前未准备好循环器而导致runtimeException时,请尝试此操作
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
// Run your task here
}
}, 1000 );
我一直在犯这个错误,直到我做了下面的事情
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();
}
}
);
}
}
Toast.makeText()
只能从主/UI线程调用。帮助您实现:
ANDROID
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
toast.show();
}
});
KOTLIN
Handler(Looper.getMainLooper()).post {
Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT).show()
}
此方法的一个优点是可以在没有活动或上下文的情况下使用它。这是因为Toast.makeText()是从工作线程调用的。它应该像这样从主UI线程调用
runOnUiThread(new Runnable() {
public void run() {
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
}
});
Toast,AlertDialogs需要在UI线程上运行,您可以在android开发中使用Asynctask来正确使用它们。但在某些情况下,我们需要自定义超时,因此我们使用线程,但在线程中我们不能像在Asynctask中那样使用Toast,AlertDialogs。因此我们需要单独的处理程序用于弹出这些
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();
}
在上面的例子中,我想在3sec中休眠我的线程,然后在mainthreadimplementhandler中显示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…希望这能帮助您在线程中显示对话框或烤面包机,最简洁的方法是使用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()
...
当我的回调试图显示一个对话框时,我遇到了同样的问题
我使用活动中的专用方法(在活动实例成员级别)解决了这个问题,这些方法使用runOnUiThread(..)
我就是这么做的
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast(...);
}
});
可视组件“锁定”到来自外部线程的更改。
因此,由于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();
});
}
我使用以下代码显示来自非主线程“c”的消息
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();
}
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);
}
};
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()
...
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();
}
});
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast(...);
}
});
public static void shortToast(String msg) {
Observable.just(msg)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(message -> {
Toast.makeText(App.getInstance(), message, Toast.LENGTH_SHORT).show();
});
}
@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();
}
}
private class MyTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
textView.setText("Any Text");
return null;
}
}
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
}
});
Handler handler2;
HandlerThread handlerThread=new HandlerThread("second_thread");
handlerThread.start();
handler2=new Handler(handlerThread.getLooper());
runOnUiThread {
// Add your ui thread code here
}
Looper.prepare() // to be able to make toast
Toast.makeText(context, "not connected", Toast.LENGTH_LONG).show()
Looper.loop()
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "YOUR_MESSAGE", Toast.LENGTH_SHORT).show();
}
});
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}
activity.runOnUiThread(() -> Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show());
new Handler(Looper.getMainLooper()).post(() -> {
// Work in the UI thread
};
Handler(Looper.getMainLooper()).post{
// Work in the UI thread
}
CoroutineScope(Job() + Dispatchers.Main).launch {
Toast.makeText(context, "yourmessage",Toast.LENGTH_LONG).show()}
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();
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();