不能在没有调用Looper.prepare()的线程中创build处理程序
以下例外是什么意思; 我该如何解决?
这是代码:
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)
你从一个工作者线程调用它。 你需要在主线程中调用Toast.makeText()
(和其他大多数处理UI的函数)。 例如,您可以使用处理程序。
在文档中查找与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(); }
其他选项:
你可以使用一个AsyncTask ,对于在后台运行的大多数东西来说效果很好。 它有挂钩,你可以打电话来表明进度,什么时候结束。
你也可以使用Activity.runOnUiThread() 。
您需要从UI线程调用Toast.makeText(...)
:
activity.runOnUiThread(new Runnable() { public void run() { Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show(); } });
这是从另一个(重复)SO答复复制粘贴。
更新 – 2016年
最好的select是使用RxAndroid
( RxAndroid
特定绑定)为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> () { @Override public void onCompleted() { // Print Toast on completion } @Override public void onError(Throwable e) {} @Override public void onNext(PojoObject pojoObject) { // Show Progress } }); }
————————————————– ————————————————– ——————————
我知道我有点晚了,但这里走了。 Android基本上工作在两个线程types,即UI线程和后台线程 。 根据android文档 –
不要从UI线程外部访问Android UI工具包来解决这个问题,Android提供了几种方法从其他线程访问UI线程。 这里是可以帮助的方法列表:
Activity.runOnUiThread(Runnable) View.post(Runnable) View.postDelayed(Runnable, long)
现在有很多方法可以解决这个问题。
我将通过代码示例来解释它:
runOnUiThread
new Thread() { public void run() { myactivity.this.runOnUiThread(new Runnable() { public void run() { //Do your UI operations like dialog opening or Toast here } }); } }.start();
LOOPER
用于为线程运行消息循环的类。 线程默认情况下没有与它们相关的消息循环; 创build一个,在要运行循环的线程中调用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
AsyncTask允许您在用户界面上执行asynchronous工作。 它在工作线程中执行阻塞操作,然后将结果发布到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 } }
处理器
处理程序允许您发送和处理与线程的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; } });
尝试这一点,当你看到由于Looper没有准备好处理程序之前,runtimeException。
Handler handler = new Handler(Looper.getMainLooper()); handler.postDelayed(new Runnable() { @override void run() { // Run your task here } }, 1000 );
我遇到了同样的问题,这里是我如何解决它:
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); }
要创buildUIHandler,您需要执行以下操作:
HandlerThread uiThread = new HandlerThread("UIHandler"); uiThread.start(); uiHandler = new UIHandler((HandlerThread) uiThread.getLooper());
希望这可以帮助。
错误原因:
工作线程用于执行后台任务,除非调用像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
。
我得到这个错误,直到我做了以下。
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(); } } ); } }
这就是我所做的。
new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { Toast(...); } });
可视化组件被“locking”来自外部线程的变化。 所以,由于吐司在由主线程pipe理的主屏幕上显示了东西,所以你需要在该线程上运行这个代码。 希望帮助:)
这种方法的一个优点是,你也可以在非活动类中使用:
new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT); } });
奇科鸟的答案为我工作。 我做的唯一的改变是在UIHandler的创build,我必须做的
HandlerThread uiThread = new HandlerThread("UIHandler");
Eclipse拒绝接受别的东西。 我想是有道理的。
uiHandler
显然也是一个全球定义的类。 我还没有声称了解Android是如何做到这一点,发生了什么,但我很高兴它的工作原理。 现在我将着手研究它,看看我能不能理解Android正在做什么,为什么要经历所有这些循环。 感谢ChicoBird的帮助。
这是因为Toast.makeText()正在从工作线程调用。 它应该是这样的主UI线程调用
runOnUiThread(new Runnable() { public void run() { Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT); } });
当我的callback尝试显示一个对话框时,我遇到了同样的问题。
我用Activity中的专用方法解决了它 – 在Activity 实例成员级别 – 使用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(); } }); }
要在线程中显示对话框或烤面包机,最简洁的方法是使用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() ...
对于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(); }); }
敬酒,AlertDialogs需要在UI线程上运行,你可以使用Asynctask在android开发中正确使用它们。但是有些情况下我们需要定制超时,所以我们使用线程 ,但是在线程中我们不能使用Toast,Alertdialogs就像我们使用在AsyncTask.So我们需要单独的处理程序popup这些。
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消息,在你的mainthread实现处理程序中。
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); } };
我在这里使用开关盒,因为如果你需要以相同的方式显示不同的信息,你可以在Handler类中使用开关盒…希望这会帮助你