Difference between Handler and Thread

Asked

Viewed 11,955 times

10

I made a test app in which I would like to see a ProgressBar updating by simulating a long-duration task. I initially tried using Handler because after some research I saw that its use was recommended:

        final int tempoDeEspera = 500;
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(tempoDeEspera);
                progressBar.setProgress(1);
                SystemClock.sleep(tempoDeEspera);
                progressBar.setProgress(2);
                SystemClock.sleep(tempoDeEspera);
                progressBar.setProgress(3);
                SystemClock.sleep(tempoDeEspera);
                progressBar.setProgress(4);
                SystemClock.sleep(tempoDeEspera);
                progressBar.setProgress(5);
            }
        });

But I only got the expected result using Thread.

        final int tempoDeEspera = 500;
        new Thread(new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(tempoDeEspera);
                progressBar.setProgress(1);
                SystemClock.sleep(tempoDeEspera);
                progressBar.setProgress(2);
                SystemClock.sleep(tempoDeEspera);
                progressBar.setProgress(3);
                SystemClock.sleep(tempoDeEspera);
                progressBar.setProgress(4);
                SystemClock.sleep(tempoDeEspera);
                progressBar.setProgress(5);
            }
        }).start();

I would like to know the details of the two implementations and the situations in which each one should be used.

1 answer

15


First, a basic concept (if you already know this part, you can skip to the last paragraph):

There is the thread main, also called UI thread, whose central function is to perform UI (user interface), that is, updating the application screen, how to display texts, images, etc. This thread should not be burdened with operations unrelated to UI that are too heavy, otherwise causing the famous ANRs, that is, screen update delay warnings that cause crashes in app responsiveness.

And there are the threads secondary (any thread other than the main), these yes suitable for heavier operations other than the UI, but which do not have direct access to the thread main and therefore it is not possible to call screen update operations directly by them; they are required Handlers for this, which are objects that "post" a UI operation in the queue of operations to be executed by thread main (this is called posting a "message" or Runnable in the main thread). The difference between a message (class Message) and a Runnable is minimal; both are snippets of executable code, of which Message stores a reference to an object that may be important to the code being executed (often this is not necessary, just pass one Runnable to the thread through the method Handler.post(Runnable)).

In your case, you have a thread secondary executing non-UU operations (the calls to sleep()) and that from time to time you need to communicate to the main thread that the UI component ProgressBar needs to be updated (this UI operation would be the call to ProgressBar.setProgress()). As already said your thread secondary has no direct access to the thread main and to post a "message" to the main thread run it should use a Handler. The code would look like this:

final Handler handler = new Handler(Looper.getMainLooper());
final int tempoDeEspera = 500;
int i;

new Thread(new Runnable() {
    @Override
    public void run() {
        for (i = 0; i < 5; i++) {
            SystemClock.sleep(tempoDeEspera);
            handler.post(new Runnable() {
                @Override
                public void run() {
                    progressBar.setProgress(i);
                }
            });
        }
    }).start();

Obs.: I didn’t test to see if this code compiles, but it serves to illustrate the concept of Handler and the difference between UI and not-UI and their threads who execute them.

Examples of heavy operations that require processing and therefore must be performed in a thread separate: I/O operations, such as network access (HTTP requests in general, such as URL access), file writing and Sqlite database, heavy math processing, etc.

A complement: in your case it worked without the Handler because the operation ProgressBar.setProgress() executes a post() internally (to ProgressBar inherits this method of View), which updates the ProgressBar in the execution queue of thread main. But not all UI components do this, so the Handler continues to be useful in many cases.

  • Nice answer! But my doubt is not about the concept of MainThread, this is pretty basic. What I’d like to know is why the version with Handler didn’t work. But I think I already know the answer: I probably have to use a post different for each setProgress right?

  • 1

    Yeah, that’s right! 'Cause while yours post occupied the UI thread, did not leave the post made internally by setProgress and added to the main thread run queue. The five setProgress then were executed quickly and in sequence without giving time to notice it visually.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.