Android: When Should I Use a Handler() and When Should I Use a Thread

Android: When should I use a Handler() and when should I use a Thread?

If whatever you are doing is "heavy" you should be doing it in a Thread. If you do not explicitly start it in its own thread, then it will run on the main (UI) thread which may be noticeable as jittery or slow to respond interface by your users.

Interestingly when you are using a thread it is often useful to also use a Handler as a means of communication between the work thread that you are starting and the main thread.

A typical Thread/Handler interaction might look something like this:

Handler h = new Handler(){
@Override
public void handleMessage(Message msg){
if(msg.what == 0){
updateUI();
}else{
showErrorDialog();
}
}
};

Thread t = new Thread() {
@Override
public void run(){
doSomeWork();
if(succeed){
//we can't update the UI from here so we'll signal our handler and it will do it for us.
h.sendEmptyMessage(0);
}else{
h.sendEmptyMessage(1);
}
}
};

In general though, the take home is that you should use a Thread any time you are doing some work that could be long running or very intensive (i.e. anything network, file IO, heavy arithmatic, etc).

Why and when should I use a handler?

Every app has its own special thread that runs UI objects such as View objects; this thread is called the UI Thread.

Considering your stopwatch example if you just add the loop inside your activity and keep the time going then it will block your UI thread and your app may become unresponsive. To overcome this problem and not to block the UI/Main thread we use separate threads to do such ongoing/long tasks.

So what he does is created a Handler which will do the long running task and it sends the update to UI thread to update textView when required.

When to use handler.post() & when to new Thread()

You should use Handler.post() whenever you want to do operations on the UI thread.

So let's say you want to change a TextView's text in the callback. Because the callback is not running on the UI thread, you should use Handler.post().

In Android, as in many other UI frameworks, UI elements (widgets) can be only modified from UI thread.

Also note that the terms "UI thread" and "main thread" are often used interchangeably.


Edit: an example of the long-running task:

mHandler = new Handler();

new Thread(new Runnable() {
@Override
public void run () {
// Perform long-running task here
// (like audio buffering).
// You may want to update a progress
// bar every second, so use a handler:
mHandler.post(new Runnable() {
@Override
public void run () {
// make operation on the UI - for example
// on a progress bar.
}
});
}
}).start();

Of course, if the task you want to perform is really long and there is a risk that user might switch to some another app in the meantime, you should consider using a Service.

Which should i use Handler or Thread?

Handler and Thread do NOT do the same thing.

A Handler processes a Runnable, either now or in the near future (if you use postDelayed). It does this on the Thread that it was created on.

A Thread is a separate line of execution- its a series of instructions that happen at the same time as other Threads. A thread is how you get two things to happen on a computer at the same time.

While both take a Runnable as a parameter, they do totally different things. Which one is appropriate for you? If you want to do something in N seconds on the UI thread, like updating the UI, use a Handler. If you want to do extensive background processing or network requests, use a Thread.

difference between Thread and Handler

The same: you can both execute task asynchronously without blocking your current code,

The difference: Imagine you have a Runnable r = new Runnable{...}

  • When you use new Thread(r).start(), you actually created a new thread and run task asynchronously.

  • When you use new Handler().post(r) (or Message), you added the Runnable object to Looper and execute the code later in the same thread.

A Thread, generally MainThread or UIThread contains a Looper. When MainThread runs, it will loop the Looper and execute Runnable one by one.

When Thread is preferred:

When you're doing a heavy work like network communication, or decoding large bitmap files, a new thread is preferred. If a lot of thread is needed, maybe ExecutorService is preferred further.
https://developer.android.com/reference/java/util/concurrent/ExecutorService.html

When Handler is preferred:

When you want to update UI objects (like TextView text) from other thread, it is necessary that UI objects could only be updated in UI Thread.
Also, when you just want to run some light code later (like the delay for 300ms) you can use Handler because it's lighter and faster.

Please also refer to Handler vs AsyncTask vs Thread

Is a Handler a Thread or not, and what is the role of a Looper with Handlers and Threads?

premise : A Handler is not a Thread.

A Looper is an Object associated with the Thread from which it is created. As you can guess by it's name a Looper is going to loop over something, but looping over what ? Over a message queue also associated with the same thread.

Next question is: How can I put something in this message queue ?

And here is the Handler. A Handler is always associated with a Looper (which one ? we will see it later). The Handler can play 2 roles (and that's maybe why it is confusing)

First role of the Handler : you must use it to post messages to it's associated Looper (in fact to it's message queue). You can use one of the various Handler.sendMessage* (or Handler.post*) methods to do that. (and note the sendMessageDelayed/postDelayed methods allowing you to post a Message/Runnable to be handled in future)

What is the Looper associated with a Handler ? Very easy : the Looper of the current Thread if you don't specify it; but you can use the constructor with a Looper : new Handler(Looper looper) and in this case the handler is associated with looper in argument.

At this point, we know that :

  • a Looper is associated with one and only one Thread
  • a Looper loops over it's associated message queue
  • as a consequence : there is one message queue associated with one Thread (as soon as we have a Looper for the Thread)
  • a Handler is always associated with one Looper
  • a Handler can be used to post message to the message queue

Now, let's see the second part : the message processing/message handling.

First, let's look at the Looper looping over it's message queue.

Is there is a message in the queue ? Yes (i.e. at some point, a Handler has posted it.)
Is it time to handle this message (if it was posted with postDelayed) ? If not, wait a little. If it is time : let's dispatch this message.

Remember that I told that the Handler have 2 roles... and here is the second role of the Handler : a Handler (as indicated by it's name) can handle messages. To be able to handle custom messages you must subclass the Handler class and implements the handleMessage(Message) method.

So, the Looper will simply call the handleMessage of the Handler who posted the message and it's job (i.e. dispatching the messages) is finished (the Looper can move on to the next Message in the queue).

At this point you may ask yourself : "OK I see the interest of delayed messages, but why should I use all this stuff for things to do immediatelly ?"

Remember that the Looper is associated with one Thread and the handleMessage will be called in this Thread. On the other hand, the Handler.post* can be called from another thread. So this mechanism is also very convenient to schedule a job in thread X from thread Y. (particularly useful if the job is affecting the UI and MUST be run in the UI-Thread)

Final note

  • UI-thread is a first class citizen :

On Android, there is a main Looper associated with the main Thread (i.e. the UI-thread). You can get a reference to it with Looper.getMainLooper(), so you create a Handler associated with the main Looper with :

Handler myHandler = new Handler(Looper.getMainLooper());

and with that you can post a message from any thread to the UI-thread

  • Should you really use messages and subclassing Handler to use this ? No (not always)

You don't always need to create message explicitly to use this mechanism. You can easily post a Runnable to a Handler and in this case you don't even need to override the handleMessage(Message) because the default implementation of the Handler will simply execute the Runnable (under the hood : a message is created with the Runnable associated to it)

  • Looper must be prepared (to receive messages)

By default there is no Looper on every thread (by default, there is only a prepared one in the UI-Thread). To prepare a Looper for the current thread : call Looper.prepare()

how to use handler on android concurrently?

Handler can't work in an asynchronous way in the same thread.

A handler allows you to send and process Messages and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread’s message queue. The MessageQueue is a queue that has a list of tasks (messages, runnable) that will be executed in a certain thread. When you create a new handler, it is bound to the thread/message queue of the thread that is creating it — from that point on, it will deliver messages and runnables to that message queue and executes them as they come out of the message queue. The looper is responsible for keeping the thread alive. It is a kind of worker that serves a MessageQueue for the current thread. Looper loops through a message queue and sends messages to corresponding threads to process.

see this image for a clear concept

When a handler is created, it can get a Looper object in the constructor, which indicates which thread the handler is attached to. So attaching handlers to the different threads can make them Asynchronous. Here you are posting the runnables in same thread MessageQueue with same time delay so it will execute sequentially.

To know more knowledge about Handler, Thread, Looper, and Message Queue you can read this blog

Best use of HandlerThread over other similar classes

Here is a real life example where HandlerThread becomes handy. When you register for Camera preview frames, you receive them in onPreviewFrame() callback. The documentation explains that This callback is invoked on the event thread open(int) was called from.

Usually, this means that the callback will be invoked on the main (UI) thread. Thus, the task of dealing with the huge pixel arrays may get stuck when menus are opened, animations are animated, or even if statistics in printed on the screen.

The easy solution is to create a new HandlerThread() and delegate Camera.open() to this thread (I did it through post(Runnable), you don't need to implement Handler.Callback).

Note that all other work with the Camera can be done as usual, you don't have to delegate Camera.startPreview() or Camera.setPreviewCallback() to the HandlerThread. To be on the safe side, I wait for the actual Camera.open(int) to complete before I continue on the main thread (or whatever thread was used to call Camera.open() before the change).


So, if you start with code

try {
mCamera = Camera.open(1);
}
catch (RuntimeException e) {
Log.e(LOG_TAG, "failed to open front camera");
}
// some code that uses mCamera immediately

first extract it as is into a private method:

private void oldOpenCamera() {
try {
mCamera = Camera.open(1);
}
catch (RuntimeException e) {
Log.e(LOG_TAG, "failed to open front camera");
}
}

and instead of calling oldOpenCamera() simply use newOpencamera():

private void newOpenCamera() {
if (mThread == null) {
mThread = new CameraHandlerThread();
}

synchronized (mThread) {
mThread.openCamera();
}
}
private CameraHandlerThread mThread = null;
private static class CameraHandlerThread extends HandlerThread {
Handler mHandler = null;

CameraHandlerThread() {
super("CameraHandlerThread");
start();
mHandler = new Handler(getLooper());
}

synchronized void notifyCameraOpened() {
notify();
}

void openCamera() {
mHandler.post(new Runnable() {
@Override
public void run() {
oldOpenCamera();
notifyCameraOpened();
}
});
try {
wait();
}
catch (InterruptedException e) {
Log.w(LOG_TAG, "wait was interrupted");
}
}
}

Note that the whole notify() -- wait() inter-thread communication is not necessary if you don't access mCamera in the original code immediately after opening it.

Update: Here the same approach is applied to accelerometer: Acclerometer Sensor in Separate Thread

Why use Handler?

From the documentation of View:

You must always be on the UI thread when calling any method on any
view.
If you are doing work on other threads and want to update the
state of a view from that thread, you should use a Handler.

In your example, when you've to call the dismiss() method on the ProgressDialog, as per the above documentation, you must do so from the UI thread. The messageHandler is initialized to an instance of a Handler when the HandlerThread class is instantiated (presumably on the UI thread).

From the documentation of Handler:

Each Handler instance is associated with a single thread and that
thread's message queue. When you create a new Handler, it is bound to
the thread / message queue of the thread that is creating it -- from
that point on, it will deliver messages and runnables to that message
queue and execute them as they come out of the message queue.

So to communicate with the UI thread from your new thread, just post a message to the Handler created on the UI thread.

If you call methods on a View from outside the UI thread, it invokes undefined behaviour, which means, it may appear to work fine. But it's not always guaranteed to work fine.



Related Topics



Leave a reply



Submit