csdnceshi80
胖鸭
2010-10-06 17:18
浏览 1.1k

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

What does the following exception mean; how can I fix it?

This is the code:

Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);

This is the exception:

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)

转载于:https://stackoverflow.com/questions/3875184/cant-create-handler-inside-thread-that-has-not-called-looper-prepare

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

19条回答 默认 最新

  • weixin_41568131
    10.24 2010-10-06 17:20
    已采纳

    You're calling it from a worker thread. You need to call Toast.makeText() (and most other functions dealing with the UI) from within the main thread. You could use a handler, for example.

    Look up Communicating with the UI Thread in the documentation. In a nutshell:

    // 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();
    }
    

    Other options:

    You could use an AsyncTask, that works well for most things running in the background. It has hooks that you can call to indicate the progress, and when it's done.

    You could also use Activity.runOnUiThread().

    点赞 评论
  • csdnceshi73
    喵-见缝插针 2011-11-30 19:35

    I ran into the same problem, and here is how I fixed it:

    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);
    }
    

    To create the UIHandler, you'll need to perform the following:

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

    Hope this helps.

    点赞 评论
  • csdnceshi79
    python小菜 2011-12-23 13:47

    The answer by ChicoBird worked for me. The only change I made was in the creation of the UIHandler where I had to do

    HandlerThread uiThread = new HandlerThread("UIHandler");
    

    Eclipse refused to accept anything else. Makes sense I suppose.

    Also the uiHandler is clearly a class global defined somewhere. I still don't claim to understand how Android is doing this and what is going on but I am glad it works. Now I will proceed to study it and see if I can understand what Android is doing and why one has to go through all these hoops and loops. Thanks for the help ChicoBird.

    点赞 评论
  • csdnceshi74
    7*4 2012-03-22 02:11

    You need to call Toast.makeText(...) from the UI thread:

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

    This is copy-pasted from another (duplicate) SO answer.

    点赞 评论
  • csdnceshi64
    游.程 2013-05-16 07:40

    Reason for an error:

    Worker threads are meant for doing background tasks and you can't show anything on UI within a worker thread unless you call method like runOnUiThread. If you try to show anything on UI thread without calling runOnUiThread, there will be a java.lang.RuntimeException.

    So, if you are in an activity but calling Toast.makeText() from worker thread, do this:

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

    The above code ensures that you are showing the Toast message in a UI thread since you are calling it inside runOnUiThread method. So no more java.lang.RuntimeException.

    点赞 评论
  • csdnceshi70
    笑故挽风 2013-06-02 19:32

    UPDATE - 2016

    The best alternative is to use RxAndroid (specific bindings for RxJava) for the P in MVP to take charge fo data.

    Start by returning Observable from your existing method.

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

    Use this Observable like this -

    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
        }
    });
    }
    

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

    I know I am a little late but here goes. Android basically works on two thread types namely UI thread and background thread. According to android documentation -

    Do not access the Android UI toolkit from outside the UI thread to fix this problem, Android offers several ways to access the UI thread from other threads. Here is a list of methods that can help:

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

    Now there are various methods to solve this problem.

    I will explain it by code sample:

    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

    Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.

    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 allows you to perform asynchronous work on your user interface. It performs the blocking operations in a worker thread and then publishes the results on the UI thread, without requiring you to handle threads and/or handlers yourself.

    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

    A Handler allows you to send and process Message and Runnable objects associated with a thread's 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;
        }
    });
    
    点赞 评论
  • csdnceshi64
    游.程 2014-06-13 07:26

    Try this, when you see runtimeException due to Looper not prepared before handler.

    Handler handler = new Handler(Looper.getMainLooper()); 
    
    handler.postDelayed(new Runnable() {
      @override
      void run() {
      // Run your task here
      }
    }, 1000 );
    
    点赞 评论
  • csdnceshi68
    local-host 2014-11-20 13:09

    I was getting this error until I did the following.

    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();
                }
            }
        );
    }
    

    And made this into a singleton class:

    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();
                    }
                }
            );
        }
    
    }
    
    点赞 评论
  • weixin_41568196
    撒拉嘿哟木头 2016-01-24 00:27

    Toast.makeText() should be called from Main/UI thread. Looper.getMainLooper() helps you to achieve it:

    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
        }
    });
    

    An advantage of this method is that you can use it in non-Activity (or without Context) classes as well.

    点赞 评论
  • csdnceshi72
    谁还没个明天 2016-05-15 08:25

    This is because Toast.makeText() is calling from a worker thread. It should be call from main UI thread like this

    runOnUiThread(new Runnable() {
          public void run() {
            Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
          }
     });
    
    点赞 评论
  • csdnceshi79
    python小菜 2016-07-05 10:07

    Toast, AlertDialogs needs to run on UI thread, you can use Asynctask to use them properly in android development.but some cases we need to customize the time outs, so we use Threads, but in threads we cannot use Toast,Alertdialogs like we using in AsyncTask.So we need separate Handler for popup those.

    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();
    }
    

    in Above example i want to sleep my thread in 3sec and after i want to show a Toast message,for that in your mainthread implement 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);
           }
    };
    

    I used switch case here, because if you need to show different message in same way, you can use switch case within Handler class...hope this will help you

    点赞 评论
  • weixin_41568110
    七度&光 2016-08-26 19:07

    To display a dialog or a toaster in a thread, the most concise way is to use the Activity object.

    For example:

    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()
    ...
    
    点赞 评论
  • csdnceshi78
    程序go 2017-01-12 20:48

    I was running into the same issue when my callbacks would try to show a dialog.

    I solved it with dedicated methods in the Activity - at the Activity instance member level - that use 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();
            }
        });
    }
    
    点赞 评论
  • weixin_41568183
    零零乙 2017-03-16 16:13

    that's what i did.

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

    Visual components are "locked" to changes from outside threads. So, since the toast shows stuff on the main screen that is managed by the main thread, you need to run this code on that thread. Hope that helps:)

    点赞 评论
  • weixin_41568208
    北城已荒凉 2017-05-05 07:24

    For Rxjava and RxAndroid User:

    public static void shortToast(String msg) {
        Observable.just(msg)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(message -> {
                    Toast.makeText(App.getInstance(), message, Toast.LENGTH_SHORT).show();
                });
    }
    
    点赞 评论
  • csdnceshi72
    谁还没个明天 2018-02-22 03:33

    First need to import given line.

    import android.os.StrictMode;
    

    And then, add below lines in onCreate() method of your Activity:

    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
    
    点赞 评论
  • weixin_41568134
    MAO-EYE 2018-03-08 07:15

    i use the following code to show message from non main thread "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();
        }
    }
    

    then use as the following:

    class myClass implements IShowMessage{
    
      showMessage("your message!");
     @Override
        public Context getContext() {
            return getApplicationContext();
        }
    }
    
    点赞 评论
  • csdnceshi74
    7*4 2018-04-20 06:15

    This usually happens when something on the main thread is called from any background thread. Lets look at an example , for instance.

    private class MyTask extends AsyncTask<Void, Void, Void> {
    
    
    @Override
    protected Void doInBackground(Void... voids) {
            textView.setText("Any Text");
            return null;
        }
    }
    

    In the above example , we are setting text on the textview which is in the main UI thread from doInBackground() method , which operates only on a worker thread.

    点赞 评论
  • csdnceshi62
    csdnceshi62 2018-09-05 10:13
     runOnUiThread(new Runnable() {
                public void run() {
                    Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
                }
            });
    
    点赞 评论

相关推荐