Best Use of Handlerthread Over Other Similar Classes

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

HandlerThread vs Executor - When is one more appropriate over the other?

The Executor class is more powerful and can use a pool of threads, whereas each Handler references a single thread. The Executor allows you to get all the scheduled tasks and cancel them if you'd like. The Handler on the other hand will not answer simple questions such as, how many tasks are waiting or give me a reference to all waiting tasks. I believe one reason that the Handler is more limited is because Android gives you access to the main Handler it uses for the UI and you could really screw up the OS if you started canceling OS tasks.

In general if you need a pool of threads or lots of power use the Executor. If you just need a nice background thread to run one task at a time use a Handler. As an example when I want to query my database I only really want one query to occur at a time and I don't want to generate an ANR so I use a Handler running on a background thread to run my queries.

I believe your choice of executor sounds appropriate since you want to handle multiple incoming requests simultaneously and a Handler can only do one at a time.

UPDATE: How to create a Handler that runs on a background thread:

In your constructor or onCreate write the following, obviously you can set the priority to whatever you like:

public class MyClass {

private Handler mBgHandler;

public MyClass() {
HandlerThread bgThread = new HandlerThread("My-Background-Handler");
bgThread.start();
mBgHandler = new Handler(bgThread.getLooper());
}
}

UPDATE: Don't forget to quit() or quitSafely() your HandlerThread when you are done with it otherwise it will remain waiting forever

Example communicating with HandlerThread

This is a working example:

HandlerThread ht = new HandlerThread("MySuperAwesomeHandlerThread");
ht.start();
Handler h = new Handler(ht.getLooper()) {
public void handleMessage(Message msg) {
Log.d(TAG, "handleMessage " + msg.what + " in " + Thread.currentThread());
};
};
for (int i = 0; i < 5; i++) {
Log.d(TAG, "sending " + i + " in " + Thread.currentThread());
h.sendEmptyMessageDelayed(i, 3000 + i * 1000);
}

UPDATE:

Make two class fields:

Handler mHtHandler;
Handler mUiHandler;

and try this:

HandlerThread ht = new HandlerThread("MySuperAwsomeHandlerThread");
ht.start();
Callback callback = new Callback() {
@Override
public boolean handleMessage(Message msg) {
if (msg.what == 0) {
Log.d(TAG, "got a meaasage in " + Thread.currentThread() + ", now sleeping... ");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, "woke up, notifying ui thread...");
mUiHandler.sendEmptyMessage(1);
} else
if (msg.what == 1) {
Log.d(TAG, "got a notification in " + Thread.currentThread());
}
return false;
}
};
mHtHandler = new Handler(ht.getLooper(), callback);
mUiHandler = new Handler(callback);
mHtHandler.sendEmptyMessageDelayed(0, 3000);

You can of course get rid of Callback interface and create two Handlers with overridden handleMessage method...

HandlerThread should i override run()?

I think you didn't get the idea of HandlerThread. HandlerThread is designed to implement thread that handles messages. What this means is that it uses Looper.loop() in its run() method (and that's why you shouldn't override it). This in turn means that you don't need to sleep in onHandleMessage() in order to prevent thread from exiting, as Looper.loop() already takes care of this.

To summarize:

  1. No, do not override run().
  2. You don't need to do anything to keep thread alive.

If you want to learn/undestand more about HandlerThread, read about Looper and Handler classes.

Is there a replacement for the Handler class?

You could always use a HandlerThread. I do not have a simple example of this handy, unfortunately.

Personally, I tend to use java.util.concurrent classes directly for things that do not involve the main application thread (e.g., LinkedBlockingQueue, ExecutorService).



Related Topics



Leave a reply



Submit