Choreographer principle analysis of Android butter plan

Source: Internet
Author: User

Engage in client development, time is a bit, but every time I think about it, I always feel that I have mastered things fragmented, not a little set in the feeling, the application layer understand, the framework of understanding a little, the idea of layering, there are some, the principle of the JVM Ah, memory allocation and management Ah, Operating mechanism AH what also know a little, every time off or nothing, on the consideration, oneself should have a main direction, to this direction focus on development, the first few goals should be very clear, we want to master Android, then about the Android view mechanism, Animation principle These are must be mastered, so, I would like to spend some time in these aspects, a good study, so as to make themselves more competitive.

Well, whether it is to understand the view mechanism, or Android animation, we should all need to have choreographer knowledge, understand how the system refresh mechanism in the end, so as to better assist in other areas. In this chapter, we will learn about the operating mechanism of choreographer in Android.

As we all know, an activity in the application layer corresponds to a root view (that is, a decorview), a windowstate, a viewrootimpl, each object is very important, is a heavyweight object during activity addition, Decorview is the root view of the current activity, which manages the view tree of the current interface, and the WindowState object is the proxy object in the system-side windowmanagerservice of the current Activity window. Viewrootimpl is responsible for the standard three-step processing and event distribution of the view, and the view drawing is guided by choreographer, choreographer's English meaning is choreographer, dance conductor, look very image. Let's start with the construction of the choreographer object, which is built in the Viewrootimpl constructor, with the following code:

From the construction method you can see that choreographer is a singleton pattern, that is, a Viewrootimpl object corresponding to a choreographer, when the interface needs to be redrawn, will be called to the Viewrootimp class of the Scheduletraversals () method, where the implementation is relatively simple, the code is as follows:

Mtraversalscheduled indicates whether a redraw has been initiated, after each scheduletraversals () method call, it is set to true, and then the next call to Dotraversal () is set to False, Then call Mchoreographer.postcallback () to add a runnable, note that the first parameter is Choreographer.callback_traversal, at choreographer Current, There are three kinds of added types, namely: Callback_input, Callback_animation, Callback_traversal, respectively, the event callback, animation callback, draw callback. The Postcallback () method calls the Postcallbackdelayed () method instead, and the last argument Delaymillis passes 0, indicating that the current redraw does not require a delay. Let's take a look at the code for the added postcallbackdelayed () method:

first, if the parameter action is NULL, the action is the object we want to callback, and the callback object is empty, what do we do? In fact, judging callbacktype, throughout the process, only defines the three types of events described above, if the incoming type value does not match, then throws a IllegalArgumentException ("Callbacktype is invalid") Abnormal. The parameters are OK, continue calling postcallbackdelayedinternal () for further processing. The code for the Postcallbackdelayedinternal () method is as follows:

This gets the current time, and then adds the time to delay, as the current callback point in time, with this point of time as the standard, add the callback object to the Mcallbackqueues[callbacktype] queue, The logic of this piece is similar to the logic of adding a message in Looper, MessageQueue, Handler, and you can learn it in comparison. Then Judge Duetime <= now, this piece of logic to see half a day, I really did not understand, Duetime will be smaller than now, that is, the Delaymillis is less than 0, and then to the top, is the current callback to be added before the last callback added, It's not a good feeling, is it? If you have a friend to understand, please answer it. Here should be the Execute Else branch, add a message to the current queue, then through the handler mechanism will be processed, here Mhandler is a Framehandler object, we look at the Framehandler code:Here the message is also relatively simple, msg_do_frame refers to the system in the absence of the use of VSync mechanism, the use of asynchronous messages to refresh the screen, of course, we must understand that the refresh here is actually just a small part of the refresh screen work, Just call back the Runnable object that was added to the Viewrootimpl method, and ultimately the draw method that calls the root view so that each child view has its own image element populated into the allocated video memory, and to be fully displayed, there is still much work to be done, Finally, the view of all windows in the Surfaceflinger class is synthesized, then rendered, and finally post to Framebuffer to be displayed, Msg_do_schedule_vsync of course means that the system uses VSync to refresh the Msg_do_schedule_callback means adding callback or Framecallback to complete the message. OK, let's continue to watch Msg_do_schedule_callback's message processing, which is called Doschedulecallback (MSG.ARG1) for processing, and MSG.ARG1 is the type of message you just added. We look at the Handlemessage () method of the code, found very simple, it is also a very good habit, our usual code, we should try to do so, so that one can see this method to do the thing, the specific processing into each detail method. Let's take a look at the implementation of the Doschedulecallback () method:The variables mtraversalscheduled in the Scheduletraversals () method of the mframescheduled and Viewrootimpl are the same, and are also judged whether the addition is currently being performed and then called ( Mcallbackqueues[callbacktype].hasduecallbackslocked (now)) determines whether callback transactions have been processed, and the method's judgment is simple, (mhead! = null && Mhead.duetime <= now), if the current queue header is not empty, and the point of the queue header element is less than the current point in time, then it is added before, it needs to be processed; Conversely, if the queue header is empty or the added point is greater than the current point in time, that is, deferred processing , no action is required. If the condition is met, call Scheduleframelocked (now) for further processing, and let's take a look at the implementation of the Scheduleframelocked () method:      This piece starts by assigning a value of mframescheduled to true, indicating that the transaction is starting to execute, then the above Doschedulecallback ( The code in the method is no longer executed. The next logic is use_vsync separate, the meaning is also very clear, is whether the system uses VSYNC refresh mechanism, it is obtained by the system properties, private static final Boolean Use_vsync =   Systemproperties.getboolean ("Debug.choreographer.vsync", true). If the VSync vertical synchronization mechanism is used, one step determines whether the current thread has a message loop, and if there is a message loop, requests the next vsync signal immediately, and if there is no message loop, requests the vsync signal through the main thread of the current process, or if the vsync mechanism is not used, The screen refresh is performed using asynchronous message inertia. Whether there is a message loop is done by calling the Isrunningonlooperthreadlocked () method, its implementation is simple, return looper.mylooper () = = Mlooper. Because when the choreographer object is created, the parameter looper is called Looper looper = Looper.mylooper () to get back, that is, the current process must have a message loop, so the judgment here is true, Two other branches: the current thread does not have a message loop and the system does not use the logic of the VSync synchronization mechanism, we do not analyze, if you are interested, you can follow your own. Enter the If branch, continue calling the Schedulevsynclocked () method for processing, its implementation is very simple, is to call Mdisplayeventreceiver.schedulevsync () to request the next VSync signal. see here, is not the sense of logic a bit more, began to disorderly, wandering, what is the system to do? Hehe, we paused to comb, the system has done so many things the ultimate goal is the next time the VSync signal arrives, will be in the choreographer of the three queues in the transaction execution, These transactions are applied to the application layer Viewrootimpl in the Scheduletraversals () method, in the choreographer, we have to put the outside of the callback in the queue, and then to request the vsync signal, Because the vsync signal is timed, you do not request, it will not talk to you, of course, you do not receive the callback, you do not know when to notify Viewrootimpl execution view measure, layout, draw, so to speak, we know what we are going to do? The first time I looked at choreographer class code, looked at half a day, is also a mess, so here about the rationale. OK, let's figure it out, go ahead, we've now added callback to the queue, and the next step is to request the vsync signal. Mdisplayeventreceiver is a Framedisplayeventreceiver object, let's take a look at its code definition:we can see here the Mtimestampnanos time definition is nanosecond level, because the vsync signal is used to synchronize the screen refresh frequency, so the demand for time is very high, only adopted the nanosecond level, if you do not understand the vsync signal generation mechanism, Can look at my previous blog: VSync vertical synchronous signal distribution and surfaceflinger response execution rendering flow analysis (a), Mdisplayeventreceiver class variables are assigned in the choreographer constructor method, We continue to look at the implementation of its Schedulevsync () method, because the Framedisplayeventreceiver class is inherited displayeventreceiver, and it does not use the Schedulevsync () method overrides, So the parent class is called:its implementation is very simple, to determine whether the descriptor mreceiverptr is legitimate, if the illegal printing of the log, do nothing, legal, continue to call the native method Nativeschedulevsync (mreceiverptr) To request a vsync signal. The Nativeschedulevsync () method is implemented in Android_view_displayeventreceiver.cpp, by defining Jninativemethod gmethods[] To define the method invocation pointer, Because this kind of code is not many, here is all put out, convenient for you to view:      Let's take a look at the definition of the Nativeschedulevsync method, {"Nativeschedulevsync", "(J) V",   (void*) Nativeschedulevsync}, here is a description of the Java method and the Jni method has a correspondence, "(J) V" inside the parentheses to denote the method's entry, the outside of the parentheses indicates that the return value J means long, And the return value V means void, about this, you can see my previous blog: JNI field descriptor "([ljava/lang/string;) v", is also reproduced others, hehe. Well, let's continue to look at the implementation of this method, which casts the Java layer descriptor into the Nativedisplayeventreceiver object, which is very familiar in the JNI. It then calls its Schedulevsync () method and finally determines whether the current request VSync signal succeeds based on the return value, and throws a RuntimeException exception if status is not 0. Obviously, we can guess from this that, normally, the returned status should be 0. Let's continue to look at the processing logic of the Nativedisplayeventreceiver::schedulevsync () method. First check the Mwaitingforvsync, if you are currently requesting a vsync signal, you do not need to repeat the request, only when the current is not requested, you need to make a new request, and then call Processpendingevents () Receiver processing in the current queue, so the method is not related to our process, here is not to expand, basically using the pipe mechanism will be in the mreceiver of the receiver read out, if you understand the Linux mechanism, We know that the pipe mechanism corresponds to two pipelines, the data in the pipeline is read out, it is removed from the pipeline, so do not need to do any removal of data at both ends of the processing, after each receiver processing is completed, set a Gotvsync = True,
*outtimestamp = Ev.header.timestamp,*outid = Ev.header.id,*outcount = Ev.vsync.count,gotvsync means that the current receiver has received a VSYNC signal notification. Well, we go back to the main flow, and after we finish processing receiver in the queue in the Schedulevsync () method, we start calling Mreceiver.requestnextvsync () to request a new vsync signal. Mreceiver is a Displayeventreceiver object, let's take a look at the implementation of the Requestnextvsync () method, because this class of code is very few, here is directly all posted out:     requestnextvsync () method calls the Meventconnection->requestnextvsync directly ( ) to request a vsync signal, the Meventconnection object is created in the constructor of the Displayeventreceiver class, meventconnection = Sf-> Createdisplayeventconnection (), SF is the Surfaceflinger object, Surfaceflinger class createdisplayeventconnection () implementation is also very simple, is to call Meventthread->createeventconnection (), which goes back to our previous blog, you can go and see. Eventthread always requests a vsync signal in an infinite loop threadloop (), and when a vsync signal is received, status_t err = Conn->postevent (event) is called for distribution. Conn is the Eventthread::connection object above, finally processed, callback to nativedisplayeventreceiver::handleevent (int receivefd, int events, void* data) method, the same processpendingevents () is called Dispatchvsync (Vsynctimestamp, Vsyncdisplayid, Vsynccount) after processing the callback in the queue Started distributing, in Nativedisplayeventreceiver::d Ispatchvsync () This method is passed through the current native layer of the execution environment Env callback to the Java layer, Env->callvoidmethod ( Mreceiverobjglobal,
Gdisplayeventreceiverclassinfo.dispatchvsync, timestamp, ID, count), Then it is recalled to the Java layer in the Dispatchvsync () method of the Displayeventreceiver class. The implementation in it is called Onvsync (), and framedisplayeventreceiver the Onvsync () method, So the Onvsync () method is implemented into the choreographer.framedisplayeventreceiver. turning a good big circle, we finally returned from the native layer. OK, we continue the Java layer down analysis, vsync signal back, we should also know that our goal is almost reached!! The Onvsync () method takes this as the object, adds a message to the Mhandler, and invokes its run () method when the message is processed. The Run method calls Doframe () directly for processing. Let's take a look at its implementation:if (Frametimenanos < Mlastframetimenanos) is satisfied, then we have missed this vsync signal, so in this case, we do not have to deal with, re-get the next signal. If not, then three more calls to Docallbacks () are distributed for three types of events, respectively. The order of three events is also the order of the definitions: Callback_input, callback_animation, Callback_traversal, which is their processing priority, the input event is first, and it is also intended to respond to the user's actions as soon as possible, but even if , the fluency of Android is not as good as iOS, of course, this reason is other aspects, we do not discuss here. Let's take a look at the implementation of the Docallbacks () method:This is where the elements of each type of event queue are taken out, and their run () method is called through for loop one by one, and the callback in the queue is reclaimed after the call is completed. And here the Callbackrecord object is we add in the Viewrootimpl class invalidateonanimationrunnable, Mconsumedbatchedinputrunnable, Mtraversalrunnable these three kinds of objects, then return to the view of the process, after receiving the vsync signal, will be callback mtraversalrunnable the Run () method, once again to launch the measure, layout, draw process, Then it is connected with the vsync signal. well, to here, our entire process has been analyzed, we hope to help you, thank you!

Choreographer principle analysis of Android butter plan

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.