[android] java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare();

I have an Android app running a thread. I want a Toast message to show with a message.

When I do this, I get the below exception:

Logcat trace:

FATAL EXCEPTION: Timer-0 
 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$TN.<init>(Toast.java:322)
 at android.widget.Toast.<init>(Toast.java:91)
 at android.widget.Toast.makeText(Toast.java:238) 

Is there a work around for pushing Toast messages from threads to the User Interface?

This question is related to android multithreading toast

The answer is


I got this error in a JobService from the following code:

    BluetoothLeScanner bluetoothLeScanner = getBluetoothLeScanner();
    if (BluetoothAdapter.STATE_ON == getBluetoothAdapter().getState() && null != bluetoothLeScanner) {
        // ...
    } else {
        Logger.debug(TAG, "BluetoothAdapter isn't on so will attempting to turn on and will retry starting scanning in a few seconds");
        getBluetoothAdapter().enable();
        (new Handler()).postDelayed(new Runnable() {
            @Override
            public void run() {
                startScanningBluetooth();
            }
        }, 5000);
    }

The service crashed:

2019-11-21 11:49:45.550 729-763/? D/BluetoothManagerService: MESSAGE_ENABLE(0): mBluetooth = null

    --------- beginning of crash
2019-11-21 11:49:45.556 8629-8856/com.locuslabs.android.sdk E/AndroidRuntime: FATAL EXCEPTION: Timer-1
    Process: com.locuslabs.android.sdk, PID: 8629
    java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
        at android.os.Handler.<init>(Handler.java:203)
        at android.os.Handler.<init>(Handler.java:117)
        at com.locuslabs.sdk.ibeacon.BeaconScannerJobService.startScanningBluetoothAndBroadcastAnyBeaconsFoundAndUpdatePersistentNotification(BeaconScannerJobService.java:120)
        at com.locuslabs.sdk.ibeacon.BeaconScannerJobService.access$500(BeaconScannerJobService.java:36)
        at com.locuslabs.sdk.ibeacon.BeaconScannerJobService$2$1.run(BeaconScannerJobService.java:96)
        at java.util.TimerThread.mainLoop(Timer.java:555)
        at java.util.TimerThread.run(Timer.java:505)

So I changed from Handler to Timer as follows:

   (new Timer()).schedule(new TimerTask() {
                @Override
                public void run() {
                    startScanningBluetooth();
                }
            }, 5000);

Now the code doesn't throw the RuntimeException anymore.


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

You can simply use BeginInvokeOnMainThread(). It invokes an Action on the device main (UI) thread.

Device.BeginInvokeOnMainThread(() => { displayToast("text to display"); });

It is simple and works perfectly for me!

EDIT : Works if you're using C# Xamarin


From http://developer.android.com/guide/components/processes-and-threads.html :

Additionally, the Android UI toolkit is not thread-safe. So, you must not manipulate your UI from a worker thread—you must do all manipulation to your user interface from the UI thread. Thus, there are simply two rules to Android's single thread model:

  1. Do not block the UI thread
  2. Do not access the Android UI toolkit from outside the UI thread

You have to detect idleness in a worker thread and show a toast in the main thread.

Please post some code, if you want a more detailed answer.

After code publication :

In strings.xml

<string name="idleness_toast">"You are getting late do it fast"</string>

In YourWorkerThread.java

Toast.makeText(getApplicationContext(), getString(R.string.idleness_toast), 
    Toast.LENGTH_LONG).show();

Don't use AlertDialog, make a choice. AlertDialog and Toast are two different things.


Here's what I've been doing:

  public void displayError(final String errorText) {
    Runnable doDisplayError = new Runnable() {
        public void run() {
            Toast.makeText(getApplicationContext(), errorText, Toast.LENGTH_LONG).show();
        }
    };
    messageHandler.post(doDisplayError);
}

That should allow the method to be called from either thread.

Where messageHandler is declared in the activity as ..

Handler messageHandler = new Handler();

I got this exception because I was trying to make a Toast popup from a background thread.
Toast needs an Activity to push to the user interface and threads don't have that.
So one workaround is to give the thread a link to the parent Activity and Toast to that.

Put this code in the thread where you want to send a Toast message:

parent.runOnUiThread(new Runnable() {
    public void run() {
        Toast.makeText(parent.getBaseContext(), "Hello", Toast.LENGTH_LONG).show();
    }
});

Keep a link to the parent Activity in the background thread that created this thread. Use parent variable in your thread class:

private static YourActivity parent;

When you create the thread, pass the parent Activity as a parameter through the constructor like this:

public YourBackgroundThread(YourActivity parent) {
    this.parent = parent;
}

Now the background thread can push Toast messages to the screen.


runOnUiThread(new Runnable(){
   public void run() {
     Toast.makeText(getApplicationContext(), "Status = " + message.getBody() , Toast.LENGTH_LONG).show();
   }
 });

this works for me


Examples related to android

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How to implement a simple scenario the OO way My eclipse won't open, i download the bundle pack it keeps saying error log getting " (1) no such column: _id10 " error java doesn't run if structure inside of onclick listener Cannot retrieve string(s) from preferences (settings) strange error in my Animation Drawable how to put image in a bundle and pass it to another activity FragmentActivity to Fragment A failure occurred while executing com.android.build.gradle.internal.tasks

Examples related to multithreading

How can compare-and-swap be used for a wait-free mutual exclusion for any shared data structure? Waiting until the task finishes What is the difference between Task.Run() and Task.Factory.StartNew() Why is setState in reactjs Async instead of Sync? What exactly is std::atomic? Calling async method on button click WAITING at sun.misc.Unsafe.park(Native Method) How to use background thread in swift? What is the use of static synchronized method in java? Locking pattern for proper use of .NET MemoryCache

Examples related to toast

How to create Toast in Flutter? java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(); Custom toast on Android: a simple example Use Toast inside Fragment Call to getLayoutInflater() in places not in activity How to display Toast in Android? How to change position of Toast in Android?