An Android application window contains a lot of UI elements, which are organized in a tree structure, where there is a parent-child relationship where the child UI element is inside the parent UI element, so before drawing the UI of an Android application window, We first determine the size and position of each child UI element within the parent UI element. The process of determining the size and position of individual child UI elements within a parent UI element is also known as the measurement process and layout process. As a result, the UI rendering process for the Android application window can be divided into three stages of measurement, layout, and drawing, as shown in 1:
From the creation process analysis of the View object in the previous Android application window (Activity), you can see that the top-level view of the Android application window is a UI element of type Decorview, and step 3 of the process of creating a drawing surface (surface) from the previous Android application window (the Activity) is also known that this top-level view is ultimately determined by the member function Performtraversals of the Viewroot class to initiate the measurement, Layout and drawing operations, these three operations are implemented by the member functions of the Decorview class, measure and layout, and the member function draw of the Viewroot class, respectively.
Next, we will analyze the measurement, layout, and drawing process of the Android application window, starting with the member functions measure and layout of the Decorview class and the member function draw of the Viewroot class, respectively.
1. The measurement process of the Android application window
The member function measure of the Decorview class is inherited from the parent view, so we begin to analyze the measurement process of the application window from the member function measure of the view class, as shown in 2:
The parameter child is used to describe the current sub-view to measure the size, the parameters Parentwidthmeasurespec and Parentheightmeasurespec are used to describe the maximum width and height that the current sub-view can obtain, The parameters widthused and heightused are used to describe the width and height that the parent window has used . The member function of the ViewGroup class Measurechildwithmargins must take into account the above parameters, as well as the size and margin values set by child view currently being measured. There is also the padding value set by the current view container, which comes to the correct width childwidthmeasurespec and height childheightmeasurespec for child views currently being measured, This is done by calling another member function of the ViewGroup class Getchildmeasurespec.
After you have obtained the correct width childwidthmeasurespec and height childheightmeasurespec for the child view that is currently being measured, you can call its member function measure to set its size, i.e. execute the previous step 1 of the operation. Note that if the child view currently being measured is also a view container, then it repeats the steps 2 and step 3 (recursion) until the size of all its descendants ' views is measured.
Now that we have analyzed the process of measuring the Android application window, we continue to analyze the layout of the Android application window.
2. The layout process of the Android application window
The member function layout of the Decorview class is inherited from the parent view, so we begin to analyze the layout process of the application window from the member function layout of the view class, as shown in 3:
The member function layout of the view class first calls the other member function setframe to set the position and size of the current view. After the setting is complete, the return value of the member function Setframe of the view class will be equal to true if the size or position of the current view changes compared to the last. In this case, the member function layout of the view class will continue to call another member function onlayout to re-layout the child view of the current view.
In addition, if the layout_required bit of the member variable mprivateflags of the view class is not equal to 0 at this point, it also means that the current view needs to re-layout its child view, so The member function layout of the view class will also call another member function, OnLayout.
The member function layout of the view class finally also sets the force_layout bit of the member variable mprivateflags to 0, because the layout of the current view and its child views is now up-to-date.
The member function of the Framelayout class onlayout each sub-view of the current view through a for loop . If a child view is visible, the member function of the Framelayout class onlayout the position of the upper-left corner of the application window based on the current view's area of the child view and the gravity property it sets (Childeleft,childtop).
When a child view is determined in the upper-left corner of the application window, and then combined with the width and height that it determines in the previous measurement process, we can completely determine its layout in the application window, That is, you can call its member function layout to set its position and size, which is exactly what the previous step 1 does. Note that if the child view that is currently being laid out is also a view container, it will repeat step 5 until all of its descendant views are laid out.
Now that we have analyzed the layout of the Android application window, we continue to analyze the process of drawing the Android application window.
3. The process of drawing the Android application window
The member function of the Viewroot class draw first creates a canvas, then draws the UI of the Android application window on the canvas, and then gives the canvas the contents of the Surfaceflinger service to render, as shown in procedure 4:
This function is defined in the file Frameworks/base/core/java/android/view/viewroot.java.
The execution flow of the member function draw for the Viewroot class is as follows:
1. Save the drawing surface of the application window described by the member variable msurface in the variable surface so that you can then manipulate the drawing surface of the application window by using the variable surface.
2. Call the member variable mscroller the member function of the Scroller object described by Computescrolloffset to calculate whether the application window is in a rolling state. If so, then the resulting variable scrolling will be equal to true, when the member variable Mscroller describes a Scroller object member function Getcurry can get the application window on the Y axis of the immediate scroll position yoff.
3. The member variable mscrolly is used to describe where the application window should scroll on the Y axis the next time it is drawn, so if the application window is not in the rolling state, it should be set to mscrolly directly on the y-axis of the immediate scrolling position Yoff the next time it is drawn.
4. The member variable mcurscrolly is used to describe the scroll position on the y-axis when the application window was last drawn, and if its value is not equal to the value of the variable Yoff, it indicates that the application window's scroll position on the y-axis has changed. At this point, you need to save the value of the variable Yoff in the member variable mcurscrolly, and set the parameter fullredrawneeded to True, indicating that you want to redraw all areas of the application window.
5. Member variable mattachinfo the member variable of a Attachinfo object described by mscalingrequired indicates whether the application window is requesting size scaling, and if so, Then the requested size scaling factor is stored in the other member variable mapplicationscale of the Attachinfo object. The function saves these two values in the variables scalingrequired and appscale so that they can be used next.
6. The member variable mdirty describes a rectangular area that represents the dirty area of the application window, which is the area that needs to be redrawn. The function saves the dirty area in the variable dirty so that it can be used next.
7. The member variable MUSEGL is used to describe whether the application window uses the OpenGL interface directly to draw the UI. When the memory type of the application window's drawing surface equals WindowManager.LayoutParams.MEMORY_TYPE_GPU, it means that it needs to use the OpenGL interface to draw the UI so that the GPU can be used to draw the UI. When the application window needs to draw the UI directly using the OpenGL interface, another member variable, Mglcanvas, represents the canvas used by the drawing surface of the application window, which is also created through the OpenGL interface.
8. When the application window needs to draw the UI directly using the OpenGL interface, the function then draws its UI on a piece of canvas described by the member variable Mglcanvas, This is achieved by calling the member function draw of the top-level view of the Decorview that is described by the member variable Mview. Note that you also need to convert the canvas appropriately before you draw it: A. Sets the offset value of the canvas on the y-axis yoff so that the application window's scrolling state can be correctly reflected; If the value of the member variable mtranslator is not equal to NULL, that is, it points to a translator object, then the application window runs in compatibility mode, and the canvas needs to be transformed so that it correctly reflects the size of the application window; C. When the value of the variable scalingrequired equals true, it also means that the application window is running in compatibility mode, so it is necessary to modify the point density of the canvas in compatibility mode so that it can correctly reflect the resolution of the application window, noting that The dot density of the screen in compatibility mode is saved in the static member variable density_device of the Displaymetrics class. Since the conversion of the canvas above is only valid for the current drawing operation, the function needs to call the canvas's member function save after drawing to save the matrix transform stack state before it is converted so that after drawing is complete, You can call the canvas's member function restoretocount to restore the previous matrix transform stack state.
9. After using the OpenGL interface to draw the completion UI, if the value of the variable scrolling equals true, that is, the application window is in a rolling state, then it means that the application window needs to be redrawn immediately next, and that all areas need to be redrawn, so The function next sets the value of the member variable mfullredrawneeded to TRUE and calls another member function scheduletraversals to request the next redraw operation.
10. The following steps are intended for use with non-OpenGL interfaces to draw the UI, which is the focus of this article.
11. The parameter fullredrawneeded is used to describe whether all areas of the application window need to be drawn. If necessary, the size of the dirty area of the application window is set to the size of the entire application window (0,0,mwidth,mheight), where member variables mwidth and mheight represent the width and height of the application window. Note that if the size of the application window is set to a scaling factor, that is, the value of the variable appscale is not equal to 1, then you need to multiply the width mwidth and height mheight of the application window by this scaling factor before you can get the actual size of the application window.
12. After the preceding series of calculations, if the dirty area of the application window dirty is not equal to NULL, or if the application window is in the animated state, that is, the value of the member variable misanimating equals true, then the function needs to redraw the UI of the application window next. Before you draw, you first call the member function Lockcanvas on surface of a surface object that describes the drawing surface of the application window to create a canvases canvas. With this canvas, you can then invoke the member variable Mview, a member function of the top-level view of the Decorview that describes it, to draw the UI of the application window above. As in the previous 8th step, before drawing, you also need to make the appropriate A, B, and C transformations on the canvas, as well as the matrix transform stack state that you need to restore the canvas to before drawing.
13. Once the drawing is complete, the UI of the application window is reflected in the canvas that you created earlier, so you need to give it to the Surfaceflinger service to render it. This is done by invoking the member function Unlockcanvasandpost surface of a surface object that describes the drawing surface of the application window.
14. After requesting the Surfaceflinger service to render the UI of the application window, the function also needs to determine whether the value of the variable scrolling equals true. If equal, then as in the previous 9th step, the function needs to set the value of the member variable mfullredrawneeded to True, and calls another member function scheduletraversals to request the next redraw operation.
In this article, we focus only on the steps to draw the UI of the application window using a non-OpenGL interface, where the 12th and 13th steps are key. The 12th step calls the Java layer's surface class's member function Lockcanvas to create a canvas for the application window's drawing surface, and calls the member function draw of the Decorview class to draw the UI of the application window on this canvas. The 13th step calls the Java layer's surface class's member function Unlockcanvasandpost to render the canvas that was previously drawn in the application window UI to the Surfaceflinger service.
Activity Measurement (Measure), layout, and drawing (draw) Process analysis