Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Why can't I create a handler in new thread

I had a problem creating a handler in new thread. This is my code:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    new Thread(new Runnable() {
        public void run() {
            Handler handler = new Handler();
        }
    }).start();
}

But it raised an error! Can someone please explain this to me? Thanks so much!

Here are the details of my error:

09-17 18:05:29.484: E/AndroidRuntime(810): FATAL EXCEPTION: Thread-75
09-17 18:05:29.484: E/AndroidRuntime(810): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
09-17 18:05:29.484: E/AndroidRuntime(810):  at android.os.Handler.<init>(Handler.java:197)
09-17 18:05:29.484: E/AndroidRuntime(810):  at android.os.Handler.<init>(Handler.java:111)
09-17 18:05:29.484: E/AndroidRuntime(810):  at com.example.handler.MainActivity$1.run(MainActivity.java:57)
09-17 18:05:29.484: E/AndroidRuntime(810):  at java.lang.Thread.run(Thread.java:856)
like image 614
nguyenbkcse Avatar asked Sep 17 '13 17:09

nguyenbkcse


People also ask

How do you build a handler?

This example demonstrate about how to handler in Progress Dialog. Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project. Step 2 − Add the following code to res/layout/activity_main. xml.

Does handler run on main thread?

No. If you subclass Handler (or use Handler. Callback interface) your handleMessage() method will ONLY be called for messages that have been posted using your handler. The main thread is using a different handler to post/process messages so there is no conflict.

What is alternative of handler in android?

The constructor new Handler(Looper. myLooper(), callback) is the exact alternative to the aforementioned deprecated methods. All these use the local thread to execute the background task.

Is handler a thread android?

So, Android has provided handlers to make the inter-process communication easier. A handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each handler instance is associated with a single thread and that thread's message queue.


4 Answers

You could also use a HandlerThread like this:

HandlerThread thread = new HandlerThread("MyHandlerThread");
thread.start();
Handler handler = new Handler(thread.getLooper());

HandlerThreads have a Looper associated with them, so this wouldn't throw an exception.

like image 123
Alex Lockwood Avatar answered Oct 08 '22 19:10

Alex Lockwood


The Thread's lifecycle is finished right after run method returns. But since you are creating a Handler in this thread, the Handler needs the thread to be running for it to receive messages and process them.

So for this to happen, run method should not exit. Hence you need a Looper to wait indefinitely and process messages that arrive to Handler.

new Thread(new Runnable() {
        public void run() {
            Looper.prepare();
            Handler handler = new Handler();
            Looper.loop();
        }
    }).start();
like image 36
nandeesh Avatar answered Oct 08 '22 20:10

nandeesh


Short Answer: Because the thread you're trying to attach the Handler on, doesn't have a looper. And so the constructor of Handler class is throwing exception. You could have used a HandlerThread class instead, This is just a handy class provided by the Android framework.

Please read below for whats happening under the hood.

Lets first try to discuss all parts individually.

  1. Thread:

a. A thread is just a execution flow. A thread by default is suppose to just execute its runnable(if provided) or call its run method. Upon calling new Thread.start(). A thread just dies and Gc'd when the run method executes all the statement written inside the run(){ ---- }.

b. There is a concept of Looper in Android. Which basically makes the thread a blocking thread. Putting simply it just doesn't let the thread die. It goes in a blocking state and waiting for more messages to again resume its execution.

Below is how you'd setup a blocking thread i.e a thread with a looper.

  new Thread(new Runnable() {
    public void run() {
        Looper.prepare();
        Looper.loop();
    }
}).start();

Here a thread is created which doesn't just die after executing the Looper.loop() statement. Instead it loops and goes in a blocking state. Now you must be asking what is the meaning of blocking state, how the thread will come out of the blocking state ? how do i finally release this thread now ? This is where Handler comes in

  1. Handler:

a. It always attaches itself to the Looper of the thread, on which its instance is created.

b. It then processes those messages of the thread it attaches to.

Putting together thread and handlers.

new Thread(new Runnable() {
        public void run() {
            Looper.prepare();
            handler = new Handler();
            Looper.loop();
        }
    }).start();

a. How the handler gets attached to this newly created thread. b. The thread is setup as a blocking looper thread. So this is not going to die.

now, we can 1. Send message on this handler. 2. Post runnable on this handler.

Both of them will be executed on the attached thread.

You have an option to either extend the Handler class and implement method handleMessage(Message msg). or you just provide implementation of the Handler.Callback in the constructor of the handler class. In either way the handleMessage(Messages msg) will be called on the attached thread.

To quit the thread you can send a specific type of message type, and upon receiving that message you'd just call Looper.myLooper().quit()

class LooperThread extends Thread {
   public Handler mHandler;

   public void run() {
      Looper.prepare();

      mHandler = new Handler() {
          public void handleMessage(Message msg) {
              // process incoming messages here
              if(msg.what == -1){
              Looper.myLooper().quit();
              }
          }
      };

      Looper.loop();
   }
}

I hope it helped understanding the overall concept.

like image 37
Jai Pandit Avatar answered Oct 08 '22 20:10

Jai Pandit


A Handler needs to be initialised in a Looper thread, or have a Looper given to it.

Depending on what you want to do, you can set up your thread to be a Looper like so:

new Thread(new Runnable() {
    public void run() {
        Looper.prepare();
        mHandler = new Handler();
        Looper.loop();
    }
}).start();

Since the Looper is in a background thread, you cannot update the UI. You could alternativly give the Handler a Looper from another thread - in this example, the Handler can be used to update the UI:

new Thread(new Runnable() {
    public void run() {
        Handler handler = new Handler(Looper.getMainLooper());
    }
}).start();
like image 24
FunkTheMonk Avatar answered Oct 08 '22 18:10

FunkTheMonk