Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there any real performance implications of Handlers vs Threads?

Tags:

android

There have been a number of questions regarding the proper usage of Threads vs. Handlers vs. AsyncTask. (like here & here)

Those questions nicely addressed the question of when to use what. My question is more about the performance implications in certain types of cases.

As an example, I often see other people write code in which they use Threads simply to be able to schedule some code execution for the future. Whenever, I see this, I instinctively feel like refactoring the code to use a Handler and just a post a delayed runnable.

Here's an example where a Thread is used to update the seekbar for some media playing with a mediaplayer and then the way I would do it.

what I see a lot:

 if (positionTracker != null && positionTracker.isAlive()
                && !positionTracker.isInterrupted()) {
            return;
        }

        positionTracker = new Thread(new Runnable() {

            public void run() {
                int currentPosition = 0;
                int total = player.getDuration();
                while (player != null && CurrentPosition < total) {
                    try {
                        Thread.sleep(1000);
                        currentPosition = player.getCurrentPosition();
                    } catch (InterruptedException e) {
                        return;
                    } catch (Exception e) {
                        return;
                    }


                    if (someListener != null) {
                        someListener.onEvent();
                    }

                }
            }

        }, "position tracker thread");

        positionTracker.start();

And the way I like to do it:

Runnable trackPositionRunnable = new Runnable() {
            @Override
            public void run() {
                currentPosition = player.getCurrentPosition();
                if (someListener != null) {
                    someListener.onEvent();
                    mHandler.postDelayed(this, 1000);
                }
            }
        };

        mHandler.post(trackPositionRunnable);

Obviously, my preferred way is a bit easier to read and more concise. But what are the performance implications? Is one way method better, in terms of performance, than the other? If so, why?

like image 338
LuxuryMode Avatar asked Jan 09 '12 20:01

LuxuryMode


2 Answers

Each method depends on what you plan on doing in that Runnable as to whether it will be useful or not. The biggest difference between them all is whether you plan on touching the UI or not. In Android you can't touch UI components off the UI thread (your example of media player is breaking this rule with raw Thread). Because of this rule that immediately divides what you can and can't do with each method. Performance differences between these methods is negligible because time spent running your background job is going to trump any differences between them.

Handler typically use another background thread to execute logic in, but it depends which thread constructed the Handler. If the Handler was constructed on the UI Thread (in response to callback onSomething) then your Runnable will run inside the UI Thread making it ok to touch UI Components. However, if you created it off the UI thread Runnables posted to it CANNOT touch UI components. The downside to Handlers created on the UI thread means you aren't doing these in the background so if a job takes a long time to run it will lock up the UI until its done. While Handlers run from non-UI threads will fix the any issue of locking up the UI. They take more work to setup and you still have to contend with how to safely update the UI in response to your background job (ie you still have to post another runnable back to the UI Thread if you want to update the UI).

Raw threads won't lock up the UI because they are running independently from the UI thread, but you can't touch UI components on them. That means you'll have to execute any code you want to update the UI with back on the UI thread which means more code needs to be written to get the UI thread to run it. This can be very complex. Raw threads should really be avoided because of the complexity in using them.

The most common example of background tasks is waiting for a response from the server. Most libraries block until the server sends a response which means you can't call them on the UI thread or else your user will be blocked from doing anything until the server returns a call. Not only will they be blocked, but the UI can't update itself to show a spinner or otherwise look alive. This is best to push off to a background thread. Technically Handlers and Threads can do this, but Handlers have to be constructed specially so they will use a true background thread.

This is where AsyncTask trumps Handlers because it does both true background jobs and UI updates. It has a section for doing some long running operation in the background and it has a section for updating the UI from the UI thread when its done. It even has an optional progress section so you can provide any intermediate progress to the UI while the task is running. The downside of an AsyncTask is that they must have an end. Background jobs that continue to run to periodically check if something has happened, sleep and check some more aren't conducive to the AsyncTask model. However, that's not to say you couldn't use a Handler to periodically kick off AsyncTask, but just for the completeness of the discussion I mention that.

In the end using raw Threads isn't all that easy or even "better" because Handlers can do pretty much anything that Threads can do with less code. But, Handlers are tricky in determining which thread the Runnable is executing on. Most often it's the UI thread, and technically setting it up to use a non-UI thread is tricky. Both options suffer from the UI update issues in that you have to do extra work to run UI jobs at the end of true background jobs. AsyncTask is really my preferred method for doing background jobs.

like image 116
chubbsondubs Avatar answered Sep 29 '22 18:09

chubbsondubs


It is not Handler vs Threads. They are quite different things:

Thread: Is the old Java class that implements a thread of execution. As other parts of the Java APIs they are also available on Android. Notice than in late versions of the Java language they were superseeded by the Executors framework, so the recommended practice is to use Executor/Runnable, but due to it's simplicity Threads are still used sometimes.

Handler: This class is available only in Android, and it is mostly a mechanism to communicate with an existing Thread. You send the target thread Messages or Runnables, and you can also schedule this communication.

You usually need a Handler when you need to send something to a thread. This "something" can be, for instance, encapsulated data to be processed, or a Runnable to be executed in that thread. Every handler is usually associated to the current thread at the time of instantiation, unless you use a more exotic constructor. A typical use case is to schedule a repetitive task in the main thread (which is the UI thread). Notice that for scheduling a one-shot task there's an easiest way: Activity.runOnUithread.

Now for a background task that needs to be run in a thread different than the main one: in both approaches you'll have a thread running, but creating a handler means that Android will start a new Message Queue for that thread, which is something regular threads do not need to have, and because of this there will be some overhead. Thus if you need to start a thread that can run isolated without receiving information, i'd say the simple Thread is preferred. But if you need an execution queue to schedule Runnables you can choose between a Timer, an Executor, a "handled" thread, or even AlarmManager. The advantage of Handlers is that they can be attached to any already existing thread in your app, while Timer and Executors will internally launch a new dedicated thread when they are set up.

like image 20
Mister Smith Avatar answered Sep 29 '22 19:09

Mister Smith