Android Handler advanced

Source: Internet
Author: User

Now we have a problem first. We use myThreadHandler. sendEmptyMessage (0); To send a message object, how does Handler receive and process the message object? First, I will draw a data structure diagram:

 

 

From this figure, we can clearly see that after sendEmptyMessage is called, the Message object will be put into a MessageQueue queue, which belongs to a logoff object, and each logoff object passes through ThreadLocal. set (new logoff () is bound to a Thread, and the Thread to which the logoff object belongs is in logoff. the Loop method cyclically reads the Message object from the MessageQueue queue, submits the Message object to Handler for processing, and calls the dispatchMessage method of Handler.

Now let's take a look at the basic implementation code of Handler:

// Create a handler in the main thread
NormalHandler = new Handler (){
Public void handleMessage (android. OS. Message msg ){
BtnSendMsg2NormalHandler. setText ("normalHandler ");
Log. d (Constant. TAG, MessageFormat. format ("Thread [{0}] -- normalHandler handleMessage run...", Thread. currentThread ()
. GetName ()));
}
};

...
// Send the message to hanlder
MyThreadHandler. sendEmptyMessage (0 );

Now you know the process from sendEmptyMessage to handleMessage. the MessageQueue queue is transferred to the thread where the Looper is located for processing. This is an asynchronous process. Of course, the thread where the Looper is located can also be the thread where the sendEmptyMessage is located.

After reading the above, you may still be confused. So what is loaning? What is the relationship with the Handler we are going to use?

I have always stressed the use of handler in the main thread before. Why do you want to say this? Because you should create a Handler in your new thread as you did before, an error will be reported during program execution:

Java. lang. RuntimeException: Can't create handler inside thread that has not called logoff. prepare ()
At android. OS. Handler. <init> (Handler. java: 121)
At com. cao. android. demos. handles. HandleTestActivity $ MyThread $1. <init> (HandleTestActivity. java: 86)
At com. cao. android. demos. handles. HandleTestActivity $ MyThread. run (HandleTestActivity. java: 86)

Why is this error not reported in the main thread, but in the new thread? It is very simple, because the main thread has established logoff, you can open the source code of ActivityThread to see:

Public static final void main (String [] args ){
SamplingProfilerIntegration. start ();

Process. setArgV0 ("<pre-initialized> ");

Lorule. preparemainlorule ();

ActivityThread thread = new ActivityThread ();
Thread. attach (false );

Logoff. loop ();

If (Process. supportsProcesses ()){
Throw new RuntimeException ("Main thread loop unexpectedly exited ");
}

Thread. detach ();
String name = (thread. mInitialApplication! = Null)
? Thread. mInitialApplication. getPackageName ()
: "<Unknown> ";
Slog. I (TAG, "Main thread of" + name + "is now exiting ");
}

It has already done this in the main function. Why do we need to call logoff. prepareMainLooper (); Looper. loop (); let's take a look at it. In the preparemainlogoff method, a logoff object is created and bound to the current process. in the loop method, the thread establishes a Message loop mechanism, cyclically obtains the message object from MessageQueue, and CALLS batch get to ensure that each msg in MessageQueue is handled by the handler who sends the Message, then how does Handler establish a connection with logoff? The Handler constructor has the following code:

Mlogoff = logoff. mylogoff ();
If (mloiter = null ){
Throw new RuntimeException (
"Can't create handler inside thread that has not called logoff. prepare ()");
}
MQueue = mloue. mQueue;

When creating a new Handler, you need to set the mLooper member. Looper. myloler is to obtain the bound Looper object from the current thread:

Public static final logoff mylogoff (){
Return (logoff) sThreadLocal. get ();
}

If the logoff object is not created, an exception "Can't create handler inside thread that has not called logoff. prepare ()" will be thrown ()"
This is consistent with what I mentioned earlier. Therefore, to create a Handler in a new thread, We need to write it like this:

Class MyThread extends Thread {

Public void run (){
Log. d (Constant. TAG, MessageFormat. format ("Thread [{0}] -- run...", Thread
. CurrentThread (). getName ()));
// Create a new handler in other threads
Logoff. prepare (); // create the logoff object of the thread to receive messages. There is no logoff in the non-main thread. Therefore, you must use prepare () to create a logoff before creating a handler.
MyThreadHandler = new Handler (){
Public void handleMessage (android. OS. Message msg ){
Log. d (Constant. TAG, MessageFormat. format ("Thread [{0}] -- myThreadHandler handleMessage run...", Thread
. CurrentThread (). getName ()));
}
};
Looper. myLooper (). loop (); // creates a message loop and the thread does not exit.
}
}

Now, you should understand the Handler mechanism. If you have any questions, please comment on it.

In other threads, Handler uses the Logoff of the main thread.

As I mentioned earlier, to create a Handler in a new thread, you need to call lorule. prepare (). Another method is to use lorule in the main thread, so you do not need to create a lorule object:

ThreadMainLoopHandler = new Handler (loler. getMainLooper ()){
Public void handleMessage (android. OS. Message msg ){
Log. d (Constant. TAG, MessageFormat. format ("Thread [{0}] -- threadMainLoopHandler handleMessage run...", Thread
. CurrentThread (). getName ()));
}
// The handleMessage method will be executed in mainthread
};

At this time, do not perform too many operations in handleMessage, because it is executed in the main thread, it will affect the main thread to execute the ui update operation.

Use Message. callback for callback

Public void dispatchMessage (Message msg ){
If (msg. callback! = Null ){
HandleCallback (msg );
} Else {
If (mCallback! = Null ){
If (mCallback. handleMessage (msg )){
Return;
}
}
HandleMessage (msg );
}
}
The dispatchMessage definition shows that if the Message object contains a callback object, handler will not execute the handleMessage method but will execute the message. the run method defined in callback, of course, callback is still executed in the thread bound to the logoff associated with handler. In fact, the Handler. post (Runnable r) method is to add r to a msg. callback. That is to say, there is no difference between the following two methods:

1. Use Message. callback


Message msg = Message. obtain (myThreadHandler, new Runnable (){

@ Override
Public void run (){
Log. d (Constant. TAG, MessageFormat. format ("Thread [{0}] -- myThreadHandler. Message. callback. run ",
Thread. currentThread (). getName ()));
}
});
MyThreadHandler. sendMessage (msg );
2. Use Handler. post


MyThreadHandler. post (new Runnable (){

@ Override
Public void run (){
Log. d (Constant. TAG, MessageFormat. format ("Thread [{0}] -- myThreadHandler. Message. callback. run ",
Thread. currentThread (). getName ()));
}
});
Note: I wrote a test class for Handler mechanism tests.

3. Handler affects Activity finish.

In the process of development, we encountered a tricky problem, calling Activity. the finish function Acitivity does not execute the ondestory function of the life cycle. After half a day, it is found that there is a handler Member, because it has a delay message that is not processed and calls Activity. finish, the Activity will not destory immediately, so remember to clear unprocessed messages in handle before ativesfinish, so that the Activity will smoothly destory

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.