Androids Handler.post, what happens exactly

2019-04-07 12:23发布

问题:

since several days, I tried to figure out what exactly happens if I execute code in

void function(){

  //somePreExecutionCode
  new Handler().post(new Runnable(){
    @Override 
    public void run(){
       //someCode
    }
  });
}

It seems like it isn't blocking the UI, so buttons, which calls function() doesn't stuck in the clicked position until someCode has finished. But if somePreExecutionCode starts a progressBar, the progressBar is shown at exactly the same moment, when someCode has finished. I know, there are AsyncTasks for, but is there any other possibility?

And whats the difference between

new Handler().post 

and

View.post

?

回答1:

Putting it simply, there are Looper threads, for example, UI thread. Such thread has its own Looper, which runs a message loop for the thread.

Such thread, typically, has a Handler, which processes its Looper's messages - overriding public void handleMessage(Message msg) or executing a Runnable, which was posted to it's looper's message queue.

When you're creating a Handler in the context of UI thread (like you did in your code), it gets associated with UI thread's looper, so your \\someCode runs on UI thread.

I guess, in your use case new Handler().post(Runnable) and View:post(Runnable) are mostly the same, as they both add a Runnable to the UI thread message queue.

But they are not the same.

  • View:post(Runnable) will add a Runnable to the UI thread looper's message queue;
  • Handler:post(Runnable) will add a Runnable to its associated thread looper's message queue

My explanation is pretty much intuitive, so correct me anyone if I am wrong.



回答2:

When an Android application is created, system creates a main thread of execution. This thread is referred to as UI thread and all UI related operations happen on this thread in order to avoid synchronization issues.

A Looper instance is created on this thread, which has a MessageQueue data structure. The Looper will be in an infinite loop waiting to read the Message / Runnable instances posted on the MessageQueue. To add Message7 / Runnable to the MessageQueue, Handler is used.

When you create a Handler instance, it will be associated with the current thread of execution and the Looper instance created on that particular thread.

Hence when you post a message via a Handler, the Message is added to the MessageQueue, which will be read in FIFO order by Looper and will be delivered to the target.

new Handler().post() and View.post are bit different.

  • When you post Messages via View.post, you are guaranteed the Message will be posted on UI thread's MessageQueue, since it internally uses Handler instance created on UI Thread.
  • If you create Handler instance on UI thread and post the Message using it on any thread, Message will be posted to the UI thread's MessageQueue.
  • If you create Handler instance on a non-UI thread and post Messages using it, they will be posted on non-UI thread's MessageQueue.


回答3:

According to the Android View's documentation:

The Runnable will be run on the user interface thread

According to the Android Handler's documentation:

The Runnable will be run on the thread to which this handler is attached

So, in the Handler's case, you can create it in any thread you want, it's a kind of anchor that will execute the Runnable you provide in the thread it was created in.

In the View.post, you will always execute the Runnable in the uI thread.