In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly introduces the relevant knowledge of "what is the Handler source code". The editor shows you the operation process through an actual case. The method of operation is simple and fast, and it is practical. I hope this article "what is the Handler source code" can help you solve the problem.
Handler mechanism is a classic asynchronous messaging mechanism in Android, which plays a very important role in the long history of Android development. No matter we directly face the application layer or FrameWork layer, we still use quite a lot of scenarios.
Analyze the source code to find out.
Start with a common usage:
Private Button mBtnTest;private Handler mTestHandler = new Handler () {@ Override public void handleMessage (Message msg) {switch (msg.what) {case 1: mBtnTest.setText ("message received 1");}}; @ Overrideprotected void onCreate (final Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); mBtnTest = (Button) findViewById (R.id.btn_test) New Thread (new Runnable () {@ Override public void run () {try {Thread.sleep (3000); mTestHandler.sendEmptyMessage (1);} catch (InterruptedException e) {e.printStackTrace ();}}) .start ();}
Before we know more about something, we need to have an understanding of the value of it, that is, what it does, what it does when it happens or happens, and what the result will be at the end.
What we are going to discuss and study is what happened in this process, what causes it, and then what experience produces this effect.
Where will the message be sent when the Handler message-related method is called? You can see from the sample code above that the message will eventually go back to Handler and be handled by him. What we need to figure out is the process from sending to receiving this message.
Where will the message be sent?
MTestHandler.sendEmptyMessage (1)
Let's follow the sendEmptyMessage () method:
No matter how Handler sends any message, it passes through the sendMessageAtTime () method:
Public boolean sendMessageAtTime (Message msg, long uptimeMillis) {MessageQueue queue = mQueue; if (queue = = null) {RuntimeException e = new RuntimeException (this + "sendMessageAtTime () called with no mQueue"); Log.w ("Looper", e.getMessage (), e); return false;} return enqueueMessage (queue, msg, uptimeMillis);}
This method first determines whether the mQueue object of the current Handler is empty, and then calls the enqueueMessage () method, which literally means to save the message in the queue. Then take a look at the enqueueMessage () method:
Private boolean enqueueMessage (MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this; if (mAsynchronous) {msg.setAsynchronous (true);} return queue.enqueueMessage (msg, uptimeMillis);} public final class Message implements Parcelable {/ /.... Handler target;}
This method first binds the Message to the current Handler, so it's easy to understand that when you need to deal with the Message, you just throw it to the Handler that binds him. Then call the queue.enqueueMessage () method to formally join the queue, and what kind of object is the queue object? A message queue implemented by an one-way linked list. The queue.enqueueMessage () method iterates through the linked list and inserts the message into the footer to save it, while fetching the message from the queue takes out the Message in the header.
Then let's find out when and how queue was founded. Let's look at the constructor of Handler.
Public Handler (Callback callback, boolean async) {mLooper = Looper.myLooper (); if (mLooper = = null) {throw new RuntimeException ("Can't create handler inside thread that has not called Looper.prepare ()");} mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async;}
The constructor of Handler first calls the Looper.myLooper () method to see if you can get a Looper object, and if you can't get the program, it just jumps. Then get the message queue we need from the Looper object.
What kind of object is Looper, what kind of identity does it have, and what role does it play in the Handler mechanism? Take a look at the myLooper () method:
Public static @ Nullable Looper myLooper () {return sThreadLocal.get ();}
The myLooper () method fetches the Looper directly from the sThreadLocal object, while sThreadLocal is a ThreadLocal class object, and the ThreadLocal class puts it bluntly that the object stored by it is thread private.
Static final ThreadLocal sThreadLocal = new ThreadLocal ()
Call the get () method to get the Looper directly from ThreadLocal, and then it depends on when set () saves the Loooper object to ThreadLocal. Looper.prepare () method:
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 ();}
As can be seen from this source code, Looper is not only thread private but also the only irreplaceable. The MessageQueue () object is initialized when the Looper object is created, which is exactly the queue we need.
In the top sample code, we did not call the prepare () method to initialize Looper, and the program did not crash, because the Looper object was already initialized in the Main method of ActivityThread.
Public final class ActivityThread {/ /. Public static void main (String [] args) {Looper.prepareMainLooper ();} /.}
At this point, we know where the message will be sent, and now we need to know how to take the message out and give it to Handler for processing.
First, MessageQueue encapsulates the complete add (queue) and get / delete (out of queue) methods, and the MessageQueeue.next () method fetches the first message in the header of the linked list.
Message next () {/ /. For (;;) {if (nextPollTimeoutMillis! = 0) {Binder.flushPendingCommands ();} nativePollOnce (ptr, nextPollTimeoutMillis); synchronized (this) {final long now = SystemClock.uptimeMillis (); Message prevMsg = null; Message msg = mMessages; if (msg! = null & & msg.target = = null) {do {prevMsg = msg Msg = msg.next;} while (msg! = null & &! msg.isAsynchronous ());} if (msg! = null) {if (now)
< msg.when) { nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { 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 { nextPollTimeoutMillis = -1; } if (mQuitting) { dispose(); return null; } //............ } //.............. }} 代码虽然比较多,我们从第三行和第39行开始说起。next()方法实际是一个死循环,会一直从当前队列中去取Message,即使当前队列没有消息可取,也不会跳出循环,会一直执行,直到能够从队列中取到消息next()方法才会执行结束。 其次当Looper调用quit()方法,mQuitting变量为ture时会跳出死循环,next()方法返回null方法也会执行结束。 上面提到在ActivityThread中的main()方法中会初始化Looper,其实在不久之后便会开始从队列中取消息。 public static void main(String[] args) { //...... Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited");}调用Looper.loop()方法就会开始遍历取消息。public static void loop() {for (;;) { Message msg = queue.next(); // might block if (msg == null) { return; } final Printer logging = me.mLogging; if (logging != null) { logging.println(">> Dispatching to "+ msg.target +"+ msg.callback +": "+ msg.what);} final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; final long traceTag = me.mTraceTag; if (traceTag! = 0 & Trace.isTagEnabled (traceTag)) {Trace.traceBegin (traceTag, msg.target.getTraceName (msg));} final long start = (slowDispatchThresholdMs = = 0)? 0: SystemClock.uptimeMillis (); final long end Try {msg.target.dispatchMessage (msg); end = (slowDispatchThresholdMs = = 0)? 0: SystemClock.uptimeMillis ();} finally {if (traceTag! = 0) {Trace.traceEnd (traceTag);}
There is also an endless loop in the loop () method, which calls the queue.nex () method to start blocking the message, and the next () method returns null only if the Looper is stopped manually.
After the message is fetched, the dispatchMessage () method is called and the message is handed over to Handler for processing.
Msg.target.dispatchMessage (msg)
Public void dispatchMessage (Message msg) {if (msg.callback! = null) {handleCallback (msg);} else {if (mCallback! = null) {if (mCallback.handleMessage (msg)) {return;}} handleMessage (msg);}}
Not only can you set a callback interface for Handler, but you can also set Message. The handleMessage () method is called back by default.
I thought that was enough, but in fact, there is still a key problem. We are executing the loop () method in the main thread. Why doesn't the dead loop cause Activity blocking to get stuck? Check out why the main thread in Android does not know that an important method will be executed in the next () method because of the dead loop in Looper.loop ().
NativePollOnce (ptr, nextPollTimeoutMillis)
The boss made a good analysis, so I won't say any more. To mention, the delay message we send will save the length of time through the Message field / variable when, and the delay is also achieved in this way.
Message next () {final long now = SystemClock.uptimeMillis (); 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 {/. }}}
When Handler sends a message, it saves the message to the message queue MessageQueue maintained by Looper, while Looper always fetches the message from the queue. After getting the message, it will be processed by the Handler callback bound by Message.
This is the end of the content about "what is the Handler source code?" Thank you for your reading. If you want to know more about the industry, you can follow the industry information channel. The editor will update different knowledge points for you every day.
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.