Java
Android
RuntimeException
Looper
Threading

java.lang.RuntimeException Can't create handler inside thread that has not called Looper.prepare;

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

This Android exception means you tried to create or use a Handler on a thread that does not have a Looper. The main UI thread has a Looper automatically, but ordinary background threads do not, which is why this error often appears when background work tries to show a Toast, update a view, or create a plain Handler() directly.

Why Handler needs a Looper

A Handler posts messages and runnables into a thread's message queue. That queue is owned by a Looper. No Looper means no queue, and no queue means the Handler has nowhere to send work.

The main thread is special because Android prepares its Looper for you. Background threads created with new Thread(...) are not special. They start with no Looper at all.

That is why code like this fails:

java
new Thread(() -> {
    Handler handler = new Handler(); // crashes here
}).start();

Most common fix: post back to the main thread

If the code is trying to update the UI, the right fix is usually not to create a looper on the worker thread. The right fix is to post the UI work to the main thread:

java
1new Thread(() -> {
2    String result = "Finished";
3
4    Handler mainHandler = new Handler(Looper.getMainLooper());
5    mainHandler.post(() -> {
6        textView.setText(result);
7        Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
8    });
9}).start();

This is the standard solution for background work followed by UI updates. The background thread does the heavy work, then hands the UI change to the main looper.

If you are inside an Activity, runOnUiThread is another simple option:

java
1new Thread(() -> {
2    String result = "Done";
3    runOnUiThread(() -> statusText.setText(result));
4}).start();

If you really need a looper thread, use HandlerThread

Sometimes you do want a dedicated background thread with its own message queue. In that case, do not manually juggle Looper.prepare() unless you truly need low-level control. Use HandlerThread:

java
1HandlerThread workerThread = new HandlerThread("WorkerLooper");
2workerThread.start();
3
4Handler workerHandler = new Handler(workerThread.getLooper());
5workerHandler.post(() -> {
6    // background task here
7});
8
9// later, when finished with the thread
10workerThread.quitSafely();

HandlerThread is designed for exactly this use case and avoids a lot of lifecycle mistakes.

Why Looper.prepare() is rarely the best first answer

You can manually prepare a looper on a thread:

java
1new Thread(() -> {
2    Looper.prepare();
3    Handler handler = new Handler();
4    Looper.loop();
5}).start();

But this is low-level and easy to misuse. Once you call Looper.loop(), that thread enters a message loop and will not simply fall through like a normal worker thread. You must also decide how it should quit. For most app code, HandlerThread, coroutines, executors, or posting to Looper.getMainLooper() are better abstractions.

Modern Android alternatives

In modern Android code, plain Handler usage is often replaced with:

  • Kotlin coroutines with Dispatchers.Main and Dispatchers.IO
  • 'LifecycleScope or ViewModelScope'
  • executors for background work

Those APIs reduce the chance of raw threading mistakes, but the underlying rule still matters: UI updates belong on the main thread.

Common Pitfalls

The most common mistake is creating new Handler() inside a worker thread and assuming it behaves like it does on the main thread. It does not.

Another frequent cause is calling Toast.makeText(...).show() or touching views from a background callback. Those operations ultimately depend on the main thread.

Developers also sometimes add Looper.prepare() as a quick fix without understanding the lifecycle implications. That can create threads that never quit or leak resources.

Finally, do not confuse "background thread" with "handler thread". A plain Java thread has no message loop unless you explicitly create one.

Summary

  • This exception means a Handler was created on a thread without a Looper.
  • For UI updates, post work to Looper.getMainLooper() or use runOnUiThread.
  • If you need a background looper, use HandlerThread.
  • Avoid manual Looper.prepare() unless you truly need low-level control.
  • The safest rule is simple: background work off the UI thread, UI changes back on the main thread.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.