Can't create handler inside thread that has not called Looper.prepare()

Viewed 934918

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)
30 Answers

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.

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

Wonderful Kotlin solution:

runOnUiThread {
    // Add your ui thread code here
}

first call Looper.prepare() and then call Toast.makeText().show() last call Looper.loop() like:

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

Coroutine will do it perfectly

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

Java 8

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

}); 

Kotlin

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

GL

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

Now handler2 will use a different Thread to handle the messages than the main Thread.

Using lambda:

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

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.

I had the same problem and I fixed it simply by putting the Toast in onPostExecute() override function of the Asynctask<> and it worked.

You need to create toast on UI thread. Find the example below.

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

For displaying Toast message please refer to this article

Here is the solution for Kotlin using Coroutine:

Extend your class with CoroutineScope by MainScope():

class BootstrapActivity :  CoroutineScope by MainScope() {}

Then simply do this:

launch {
        // whatever you want to do in the main thread
    }

Don't forget to add the dependencies for coroutine:

org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}
org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.kotlinCoroutines}

Create Handler outside the Thread

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

I got the same problem and this code is working fine for me now.
As an example this is my code to do a task in the background and UI thread.
Observe how the looper is used:

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

Recently, I encounter this problem - It was happening because I was trying to call a function that was to do some UI stuff from the constructor. Removing the initialization from the constructor solved the problem for me.

Related