Tag: That's what public is. Block ISE update UI system arc LAN
Objective
Handler mechanism This topic, is the content of Rotten Street. But why do you have to take out "stir-fry a wave of cold"? Because I found this "cold" seems to eat is not very clear. Several questions have been thought about recently, and it has been found that the prior knowledge of the handler mechanism is too superficial. What's the problem?
- What is the significance of the existence of handler mechanism? Can I replace it in another way?
- Looper.loop (); is a dead loop, why is the main thread not blocked? What is the way to solve the problem of dead loops?
If you have a thorough understanding of handler, as well as threading knowledge. There is certainly no such doubt, because the above problems are inherently problematic.
On these two small problem, found oneself in the study road of not solid, so this period of time to re-understand a bit handler. A small preview of the next, about handler content will be a series of articles, today this article focuses on the understanding of handler, as well as the message queue thinking.
Body 1, handler mechanism for what?
As we all know, in Android development, the UI cannot be updated in a child thread.
Let's think about a question first. Why the UI cannot be updated on a child thread. If we look at the source of the view drawing, we all know that the reason why the UI cannot be updated on a child thread is that there is a method in Viewrootimpl:
void checkThread() { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); }}
It is obvious that this is an artificial limitation of an operation. So we're thinking, why is Google so limited when it comes to developing Android systems?
In fact, it is not difficult to speculate. As for threads, we all know that threads are memory-shared with threads. So if more than one child thread updates the UI at a time, it becomes an unsafe operation for drawing the UI. In order to ensure the correctness of the UI rendering, it is necessary to increase the lock, in a synchronized manner to control the problem.
However, the way of locking is obviously a way of sacrificing performance.
So is there any other plan? Apparently, Google finally chose to update the UI only in the main thread, and the handler mechanism was created. But it is not a new concept, it is the message queue. The principle of implementation is also simple: only one thread (main thread) is allowed to update the UI, the child thread puts the message in the message queue, the main thread polls the message queue, takes out the message and executes.
This is our handler mechanism.
2. Message Queuing
This single-threaded + Message Queuing model is in fact widely used. For example, in the Web front-end, for JavaScript, it is designed to determine the single-threaded model. Assuming that Javascript is designed as a multithreaded program, the manipulation of the DOM will inevitably involve competing resources. At this time can only lock, then in the client side running such a language program, resource consumption and performance will be not optimistic. But if the design is single-threaded, and supplemented by a complete asynchronous queue to achieve, then the cost of running is much smaller than the design of multithreading.
So we can see that the idea of the handler mechanism can be said to be a rather common design.
Since the essence is the message queue, is not we can write a set of message queue to feel the handler design ideas? Yes, let's move on to a simple set of message queues:
3. Handwritten Message Queuing
Let's go through the idea:
Looper created in the Messagequeue,handler and through the threadlocal to get the main thread new out of the Looper, so handler held MessageQueue, and therefore the thread is memory-sharing, So a child thread can send a message to MessageQueue through handler.
Looper.loop () The dead loop polls the MessageQueue, and gets the message back to its corresponding method.
So the whole handler mechanism is working. Next we rely on this idea, to achieve their own message queue, in order to code more concise, and handler mechanism to make a difference, I omit some operations such as threadlocal and so on.
3.1. Code implementation
Explanation after the code is over
public class MainMQ {private MyMessageQueue mMQ;
public static void main(String[] args) { new MainMQ().fun();}public void fun() { mMQ = new MyMessageQueue(); System.out.println("当前线程id:" + Thread.currentThread().getId()); new Thread(new Runnable() { @Override public void run() { // 省略try-catch Thread.sleep(3000); mMQ.post(new MyMessage(new Runnable() { @Override public void run() { System.out.println("执行此条消息的线程id:" + Thread.currentThread().getId()); } })); } }).start(); loop(); System.out.println("死循环了,我永远也不被执行~");}public void loop() { while (true) { // 省略try-catch MyMessage next = mMQ.next(); if (next == null) { continue; } Runnable runnable = next.getRunnable(); if (runnable != null) { runnable.run(); }}
}
The idea of Looper is not used here, because the Looper essence is to use threadlocal to create a Looper instance that is uniquely associated with the main thread, and to guarantee the uniqueness of the MessageQueue. After knowing this principle, this demo. In the main thread, new MessageQueue () is the same, and then the loop () method is called to poll the message in the MessageQueue, not null. A child thread is start in the main () method, and then sleep3 seconds later, the post Message is sent to MessageQueue. The effect is very simple, I guess a lot of small partners have guessed:! [] (http://i2.51cto.com/images/blog/201809/30/d9f45c6c1e12522dd0ad17e54bcb86d7.png?x-oss-process=image/ watermark,size_16,text_qduxq1rp5y2a5a6i,color_ffffff,t_100,g_se,x_10,y_10,shadow_90,type_zmfuz3pozw5nagvpdgk=) > Paste MessageQueue and Message "Javapublic class myMessageQueue {private final queue<mymessage> mqueue = new Arra Ydeque<> (); public void post (Mymessage message) {synchronized (this) {notify (); Mqueue.add (message); }} public Mymessage next () {when (true) {synchronized (this) {//omitted Try-catch if (!mqueue.isempty ()) {return mqueue.poll (); } wait (); } } }}
public class MyMessage { private Runnable mRunnable; public MyMessage(Runnable runnable) { mRunnable = runnable; } public Runnable getRunnable() { return mRunnable; }}
3.2. Thinking about existing problems
The attentive little partner may have noticed that after the loop () method executes there is a line of code that is then not printed:
System.out.println("死循环了,我永远也不被执行~");
Of course this is inevitable, after all, our loop () is a dead loop, and the code behind it is impossible to execute. In fact, after we call Looper.loop () in Activitythread, there is no code anymore.
There may be some small partners in question. Loop () loop, what happens to our life cycle callbacks in the main thread? Will not be carried out? In fact, through the message queue above, we can see: In this hand-written demo, we start a sub-thread before loop starts, and the child thread sends a message to loop to execute. Ensure the fluency of the message.
Is that the loop in our Android? Yes, there is a child thread before the loop in main starts.
Do not worry about this problem, let us next article to expand ~
End
Today this article is a comprehensive understanding of the handler mechanism of the first, most of the content is not directly cut to the handler mechanism itself, but from the outside to think about handler design. And then the content is to handler internal source code analysis.
Hope can be helpful to the small partners, if you feel a harvest, welcome to praise, collection, attention yo ~
Comprehensive understanding Handler First step: Understanding Message Queuing, handwritten Message Queuing