Handler, loiter, Message analysis, handlerloiter

Source: Internet
Author: User

Handler, loiter, Message analysis, handlerloiter

We all know that time-consuming operations should not be executed in the main thread, such as obtaining data from the server and then updating the interface. However, the interface update can only be executed in the main thread. In this case, the thread is usually enabled to obtain server data, and then the data is sent to the main thread through Handler to perform interface updates in the main thread. In general, our practices are as follows:

 1 new Thread(new Runnable() { 2   @Override 3   public void run() { 4     Looper.prepare(); 5     mHandler = new MyHandler(); 6     Message msg = new Message(); 7     msg.obj = "Text"; 8     mHandler.sendMessage(msg); 9     Looper.loop();10   }11 }).start();

 

MyHandler inherits Handler and rewrites the handleMessage (Message msg) method. The Code is as follows:

1 class MyHandler extends Handler{2   @Override3   public void handleMessage(Message msg) {4     String text = (String)msg.obj;5     mTextView.setText(text);6   }7 }

 


In the handleMessage method, you can process the data sent from the thread and update the control (mTextView. I know how to use it. I want to know how it works !!!). Let's look at the source code.

1) Let's see What lorule. prepare has done?
The prepare () method calls its overload method and passes in the parameter true.

1 private static void prepare(boolean quitAllowed) { 2   if (sThreadLocal.get() != null) {3     throw new RuntimeException("Only one Looper may be created per thread");4   }      5   sThreadLocal.set(new Looper(quitAllowed));6 }

 

SThreadLocal is a ThreadLoacl object. For ThreadLocal, you only need to know That ThreadLocal provides an independent copy of the variable for each thread that uses the variable. Therefore, each thread can change its own copy independently, it does not affect the copies corresponding to other threads. Here sThreadLocal stores the logoff object. A thread can have at most one logoff and can only be created in the prepare method. Therefore, a thread can Only call logoff. prepare once, otherwise RuntimeException ("Only one logoff may be created per thread") will be thrown ").
SThreadLocal. set (new LOD (quitAllowed); new generates a Looper and adds it to sThreadLocal.
2) what is done in the logoff constructor?

1 private Looper(boolean quitAllowed) { 2   mQueue = new MessageQueue(quitAllowed);3   mRun = true;4   mThread = Thread.currentThread();5 }

MessageQueue is a first-in-first-out Message Queue. the messages we send through handler are generated by them.

3) send messages
Now that MessageQueue is available, wait for the message to be sent. Messages sent using the handler. sendMessage method will eventually enter the following method:

 1 public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 2   MessageQueue queue = mQueue; 3     if (queue == null) { 4     RuntimeException e = new RuntimeException( 5     this + " sendMessageAtTime() called with no mQueue"); 6     Log.w("Looper", e.getMessage(), e);  7     return false; 8   } 9   return enqueueMessage(queue, msg, uptimeMillis);10 }

 

MQueue is obtained by obtaining the Logoff of the current thread in the constructor. EnqueueMessage is implemented by calling MessageQueue. enqueueMessage, which is to add messages to the queue.

 1 final boolean enqueueMessage(Message msg, long when) { 2   if (msg.isInUse()) { 3     throw new AndroidRuntimeException(msg + " This message is already in use."); 4   }  5   if (msg.target == null) { 6     throw new AndroidRuntimeException("Message must have a target."); 7   } 8  9   boolean needWake;10   synchronized (this) {11   if (mQuiting) {12     RuntimeException e = new RuntimeException(13     msg.target + " sending message to a Handler on a dead thread");14     Log.w("MessageQueue", e.getMessage(), e); 15     return false;16   }17 18   msg.when = when; 19   Message p = mMessages;20   if (p == null || when == 0 || when < p.when) {21     // New head, wake up the event queue if blocked.22     msg.next = p;23     mMessages = msg;24     needWake = mBlocked;25   } else {26     // Inserted within the middle of the queue. Usually we don't have to wake27   // up the event queue unless there is a barrier at the head of the queue28   // and the message is the earliest asynchronous message in the queue.29   needWake = mBlocked && p.target == null && msg.isAsynchronous();30   Message prev;31   for (;;) {32     prev = p;33     p = p.next;34     if (p == null || when < p.when) {35       break;36     }37     if (needWake && p.isAsynchronous()) {38       needWake = false;39     }40   }41   msg.next = p; // invariant: p == prev.next42   prev.next = msg;43   }44 }45   if (needWake) {46     nativeWake(mPtr);47   }48   return true;49 }

The method is a bit long. Focus on it. The addition of messages is actually implemented in the if else code. Message, which is a two-dimensional table. With this in mind, it is not difficult to understand the key code above. The current queue is empty, or when (the number of milliseconds since the start, plus delay) is 0, or the current message time is smaller than the time of the previous message, it is determined that there are no messages in the current queue. The Code enters the if segment. When a message exists in the queue, it enters the else and adds the message to the queue by adding elements to the queue through the queue table.
OK. The process of sending a message and adding the message to the queue has been completed. How can the message be obtained from the queue and sent to the handler for processing?
4) logoff. loop ()
The message is retrieved from the queue and handed over to handler for processing.

 1     /**                                                                                                                                                        2      * Run the message queue in this thread. Be sure to call 3      * {@link #quit()} to end the loop. 4      */ 5     public static void loop() { 6         final Looper me = myLooper(); 7         if (me == null) { 8             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 9         }10         final MessageQueue queue = me.mQueue;11 12         // Make sure the identity of this thread is that of the local process,13         // and keep track of what that identity token actually is.14         Binder.clearCallingIdentity();15         final long ident = Binder.clearCallingIdentity();16 17         for (;;) {18             Message msg = queue.next(); // might block19             if (msg == null) {20                 // No message indicates that the message queue is quitting.21                 return;22             }23 24             // This must be in a local variable, in case a UI event sets the logger25             Printer logging = me.mLogging;26             if (logging != null) {27                 logging.println(">>>>> Dispatching to " + msg.target + " " +28                         msg.callback + ": " + msg.what);29             }30 31             msg.target.dispatchMessage(msg);32 33             if (logging != null) {34                 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);

The amount is also quite long. Similarly, focus on it. Message msg = queue. next (); you can use your toes to retrieve messages from the queue. No. Msg.target.dispatchmessage(msg?msg.tar get, which is handler.
Handler. dispatchMessage is as follows:

 1     public void dispatchMessage(Message msg) {                                                                                                                 2         if (msg.callback != null) { 3             handleCallback(msg); 4         } else { 5             if (mCallback != null) { 6                 if (mCallback.handleMessage(msg)) { 7                     return; 8                 }    9             }   10             handleMessage(msg);11         }   12     }   

This shows the handleMessage we are familiar.
Close.

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.