In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
Most people do not understand the knowledge points of this article "how to apply the Handler mechanism in Android", so the editor summarizes the following content, detailed content, clear steps, and has a certain reference value. I hope you can get something after reading this article. Let's take a look at this "how to apply the Handler mechanism in Android" article.
Looper
Before using Handler, we have to initialize Looper and get Looper running.
Looper.prepare ();... Looper.loop ()
After executing the above two statements, Looper is ready to run. Let's first take a look at the corresponding source code:
Public static void prepare () {prepare (true);} private static void prepare (boolean quitAllowed) {if (sThreadLocal.get ()! = null) {throw new RuntimeException ("Only one Looper may be created per thread");} sThreadLocal.set (new Looper (quitAllowed));} private Looper (boolean quitAllowed) {mQueue = new MessageQueue (quitAllowed); mThread = Thread.currentThread ();}
You must ensure that there is one and only one Looper object in a thread, so when initializing Looper, it checks to see if the current thread has a Looper object. The initialization of Looper creates a MessageQueue. After the Looper is created, it will be put into the ThreadLocal. I'll talk about ThreadLocal later.
Public static void loop () {/ / determines whether the current thread initializes Looper final Looper me = myLooper (); if (me = = null) {throw new RuntimeException ("No Looper; Looper.prepare () wasn't called on this thread.");} final MessageQueue queue = me.mQueue;. For (;) {Message msg = queue.next (); / / might block if (msg = = null) {/ / No message indicates that the message queue is quitting. Return;}... Final long traceTag = me.mTraceTag; if (traceTag! = 0 & & Trace.isTagEnabled (traceTag)) {Trace.traceBegin (traceTag, msg.target.getTraceName (msg));} try {/ / target means Handler msg.target.dispatchMessage (msg);} finally {if (traceTag! = 0) {Trace.traceEnd (traceTag);}}. Msg.recycleUnchecked ();}}
The method is long, so only the core code is released. There is an interesting one in the omitted code: we can specify a threshold of, say, 200. when the processing of Message exceeds 200ms, Log will be output. This can help us identify some potential performance problems in development. Unfortunately, the method of setting the threshold is hidden and cannot be called directly, so there is no code here, and interested friends can look at the source code themselves.
The simplified code shows that the logic is very simple. It can be said that Looper plays the role of a bricklayer in it. Take the Message from the MessageQueue, then give it to Handler to distribute, and then go to MessageQueue to get the Message.... It is endless, just like a foolish man moving away from a mountain.
When you see this, it should feel a little wrong, because it is an endless cycle, which will occupy CPU resources all the time, and there is always a time when messages are processed. Should you return Null from the message queue after processing, and then Looper ends? Obviously not. Look at the note might block.
MessageQueue
The answer is in MessageQueue, so take a look at next ():
Message next () {... Int pendingIdleHandlerCount =-1; / /-1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) {if (nextPollTimeoutMillis! = 0) {Binder.flushPendingCommands ();} nativePollOnce (ptr, nextPollTimeoutMillis); synchronized (this) {/ / Try to retrieve the next message. Return if found. Final long now = SystemClock.uptimeMillis (); Message prevMsg = null; Message msg = mMessages; if (msg! = null & & msg.target = = null) {/ / Stalled by a barrier. Find the next asynchronous message in the queue. Do {prevMsg = msg; msg = msg.next;} while (msg! = null & &! msg.isAsynchronous ());} if (msg! = null) {if (now < msg.when) {/ / Next message is not ready. Set a timeout to wake up when it is ready. NextPollTimeoutMillis = (int) Math.min (msg.when-now, Integer.MAX_VALUE);} else {/ / Got a message MBlocked = false; if (prevMsg! = null) {prevMsg.next = msg.next;} else {mMessages = msg.next;} msg.next = null; if (DEBUG) Log.v (TAG, "Returning message:" + msg); msg.markInUse (); return msg;}} else {/ / No more messages. NextPollTimeoutMillis =-1;} / / Process the quit message now that all pending messages have been handled. If (mQuitting) {dispose (); return null;} / / If first time idle, then get the number of idlers to run. / / Idle handles only run if the queue is empty or if the first message / / in the queue (possibly a barrier) is due to be handled in the future. If (pendingIdleHandlerCount < 0 & (mMessages = = null | | now < mMessages.when)) {pendingIdleHandlerCount = mIdleHandlers.size ();} if (when pendingIdleHandlerCount = 0 will delay activating the thread once at the specified time, allowing the code to continue execution. This involves the underlying pipe pipeline and epoll mechanism, so I won't talk about it any more (actually, because I can't). This can answer the above question, when there is no message, you just need to suspend the thread, which ensures that you do not take up CPU resources while keeping the Looper loop.
Then let's take a look at how the information is extracted. There is a Message,Message class in MessageQueue and another Message member, next, which shows that Message is a single linked list structure. The order of messages is arranged in chronological order. Generally speaking, the Message we want to take is the first (let's not consider asynchronous messages here, we will talk about asynchronous messages later, and we have successfully dug a hole for ourselves). If the current time is greater than or equal to the time specified in Message, take the message out and return it to Looper. Since the value of nextPollTimeoutMillis is 0 at this time, when the previous message is processed, Looper comes to fetch the message again.
If the current time is less than the time specified in Message, set the nextPollTimeoutMilis value to wake up next time. There is another way that there is currently no message, nextPollTimeoutMillis will be set to-1, that is, suspend the thread. Don't worry, it's not that fast. Move on.
The following logic is to determine whether there is an IdleHandler currently, continue if not, suspend if it should be suspended, delay if there is a delay, and execute its queueIdle () method if there is an IdleHandler. What does this IdleHandler do? We should be able to guess a thing or two from the name, so we won't talk about it here. For some of its wonderful uses, you can see the delayed loading of Android startup optimization I wrote earlier. After the queueIdle () method is executed, the nextPollTimeoutMillis is set to 0 to see if there are any new messages in the message queue.
Handler
The process of fetching messages has been explained clearly above. Everything is ready. All we need to do is to add messages to the message queue. It is time for Handler, which we are most familiar with, to come out. There are two main ways for Handler to add messages to the queue:
Handler.sendXXX (); Handler.postXXX ()
The first is mainly to send Message, and the second is Runnable. Either way, you end up in MessageQueue's enqueueMessage () method.
Boolean enqueueMessage (Message msg, long when) {... Synchronized (this) {... Msg.markInUse (); msg.when = when; Message p = mMessages; boolean needWake; if (p = = null | | when = = 0 | | when < p.when) {/ / New head, wake up the event queue if blocked. Msg.next = p; mMessages = msg; needWake = mBlocked;} else {/ / Inserted within the middle of the queue. Usually we don't have to wake / / up the event queue unless there is a barrier at the head of the queue / / and the message is the earliest asynchronous message in the queue. NeedWake = mBlocked & & p.target = = null & & msg.isAsynchronous (); Message prev; for (;;) {prev = p; p = p.next.if (p = = null | | when < p.when) {break;} if (needWake & & p.isAsynchronous ()) {needWake = false;} msg.next = p; / / invariant: P = = prev.next prev.next = msg;} / / We can assume mPtr! = 0 because mQuitting is false. If (needWake) {nativeWake (mPtr);}} return true;}
Normally, when we send a message through Handler, we get a boot time through SystemClock.uptimeMillis (), and then MessageQueue sorts the Message according to that time. So there are two cases in the enqueueMessage () method, one that can be inserted directly at the head of the line. One is to line up in the middle, need to traverse, and then find a suitable pit to insert. When = = 0 corresponds to the sendMessageAtFrontOfQueue () and postAtFrontOfQueue () methods of Handler. The role of needWake is to wake up the Loop thread as appropriate.
One thing that has not been mentioned above is that after Looper takes the Message from the MessageQueue, it will hand over the message to the Handler for distribution.
Public void dispatchMessage (Message msg) {if (msg.callback! = null) {handleCallback (msg);} else {if (mCallback! = null) {if (mCallback.handleMessage (msg)) {return;}} handleMessage (msg);}}
The priority order is the callback that comes with Message, then the callback that comes with Handler, and finally the callback handleMessage ().
ThreadLocal
I still remember that there is a ThreadLocal in Looper. I put it at the end because it can be taken out separately and do not want to interfere with the whole process.
ThreadLocal is a data storage class, and the most amazing thing about it is that it is obviously the same ThreadLocal object, but different objects can be stored in different threads, such as "Hello" in thread An and "World" in thread B. They don't interfere with each other.
In the Handler mechanism, because a Looper corresponds to a thread, it is most appropriate to store the Looper in ThreadLocal.
The commonly used ThreadLocal price comparison methods are set () and get (). Let's take a look at how it works.
Public void set (T value) {Thread t = Thread.currentThread (); ThreadLocalMap map = getMap (t); if (map! = null) map.set (this, value); else createMap (t, value);}
The first thing is to get the ThreadLocalMap, set the value directly if you can find it, and create one if you can't find it.
ThreadLocalMap getMap (Thread t) {return t.threadLocals;}
If you see it here, you can probably understand. There is a ThreadLocalMap object in each thread Thread. Through the ThreadLocal.set () method, you are actually going to get the ThreadLocalMap in the current thread, and the ThreadLocalMap you get is naturally different from thread to thread.
Let's see what the origin of this ThreadLocalMap is. There is a sentence in the notes of the class:
ThreadLocalMap is a customized hash map suitable only for maintaining thread local values.
You can see from the comments that this is a custom HashMap, and its Entry class specifies that Key can only be of type ThreadLocal. So just think of it as a HashMap.
The get () method is also easy to understand, just taking the value out of the Map. Just take a look at it.
Public T get () {Thread t = Thread.currentThread (); ThreadLocalMap map = getMap (t); if (map! = null) {ThreadLocalMap.Entry e = map.getEntry (this); if (e! = null) {@ SuppressWarnings ("unchecked") T result = (T) e.value; return result;}} return setInitialValue () } the above is the content of this article on "how to apply the Handler mechanism in Android". I believe you all have a certain understanding. I hope the content shared by the editor will be helpful to you. If you want to know more about the relevant knowledge, please follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.