If you want to optimize something, you first need to know how it works. The layout is displayed on the screen by drawing.

Draw the principle

The layout is drawn using the CPU and GPU.

1. CPU and GPU

  • The CPU is responsible for calculating the displayed content. Therefore, if the content is repeated, it will cause repeated calculation and waste CPU resources
  • The GPU is responsible for rasterization

Android provides two drawing methods: software drawing and hardware drawing.

Hardware rendering is optimized according to the properties of hardware, so it is more efficient than software rendering. But the burden is power consumption, increased memory, and some unsupported ports.

2. Android Graphics framework

A graphics framework is the equivalent of a toolbox for drawing. The tools inside are as follows:

  • OpenGL ES: Brushes
  • Surface: canvas
  • View: Content to draw
  • Window: View container, and connect to Surface
  • WindowManager: Manager of Windows and connects to SurfaceFlinger
  • Graphic Buffer: An artboard with a Buffer mechanism
  • SurfaceFlinger: Displays the output, syntheses the Surface provided by Windows Manager to the display by Hardware Composer

3, Android display principle

The application will be measured, laid out, drawn surface cache data, using SurfaceFlinger to render the data to the screen, through the system’s refresh mechanism to refresh the data.

1.1 Drawing Principle

  • 1. Viewrotimpl measures and layouts each View recursively through performTraversals() to determine its size and position. So, the deeper you go, the more elements you have, the more time it takes.

  • 2. If the application layer of the system layer wants to draw the information of the View after calculation on the screen, it needs to be realized by SurfaceFlinger service of the system layer. The process is as follows:

    1. Respond to client events, create Layer and establish connection with client Surface; 2. Accept client data and properties, modify Layer properties, such as size, color transparency, etc. 3

The SurfaceFlinger system process and application process use anonymous shared memory SharedClient. Each application and SurfaceFlinger create a SharedClient. Each SharedClient can create 31 SharedBufferStacks, and each SharedBufferStack corresponds to a Surface, i.e. a window. So, each application can create 31 Windows.

In the process of drawing, THE CPU first prepares data and delivers it to the CPU for rendering through the Driver layer. The CPU is mainly responsible for the calculation of data including Measure, Layout, Record and Execute, while the GPU is responsible for Rasterization and rendering. Because the graphics API does not allow the CPU to communicate directly with the GPU, the connection is made through a graphics-driven middle layer. The graphics driver maintains a queue, and the CPU adds the display list (list of data to display) to the queue, and the GPU draws the data from the queue for drawing, and finally displays it on the screen.

The Android system signals VSYNC every 16ms to trigger a rendering of the UI, which, if successful each time, should achieve the 60FPS required for smooth graphics.

1.2 Refresh Mechanism

This can be accomplished primarily through three core mechanisms, namely vertical synchronization (timed interrupts), triple caching (caching), and Choreographer (scheduling).

Why Project Butter? Resolve the issue of out-of-sync refresh.

Why use double buffering? On Linux, the Framebuffer is usually used for display output. When the user process updates the data in the Framebuffer, the display driver updates the values of each pixel in the Framebuffer to the screen. However, if the data in the Framebuffer is updated before the last frame is displayed, the data in the Framebuffer is updated again. Will bring residual shadow problems, users will feel flicker, so the use of double buffering technology.

What does double buffering mean? Double-buffering means using two buffers (in the SharedBufferStack mentioned above), one called the Front Buffer and the other called the Back Buffer. The UI is always drawn in the Back Buffer, then swapped with the Front Buffer and rendered to the display device. That is, io_ctl is used to tell the display device to switch the buffer only when the data of another buffer is ready.

What does Choreographer do? When a VSYNC signal is received, the user-set callback function is called. CALLBACK_INPUT, CALLBACK_ANIMATION, and CALLBACK_TRAVERSAL are the callback types in descending order of priority.

When the first frame of data is not processed in time, why can’t the CPU start working at the second 16ms when VSync arrives? Because there are only two buffers; So after version 4.1, there was a third Buffer: Triple Buffer. It takes advantage of the idle CPU/GPU wait time to prepare data ahead of time that is not necessarily used.

Note: Unless necessary, only double buffering is used in most cases. Also, more buffers are not always better, so balance them out for the best.

With all the optimizations Google has made, why do apps still lag in actual development? The thread priority for VSync interrupt processing must be the highest; otherwise, even if a VSync interrupt is received and cannot be handled in a timely manner, it is futile.

1.3 Causes of lag

  • Drawing tasks are too heavy and it takes too long to draw a frame of content
  • The main thread is too busy, so the VSync signal does not have data ready, resulting in frame loss.

4, RenderThread

In the Display process of The Android system, although we make use of the graphics high-performance computing capability of the GPU, the calculation of Display, drawing by GPU and Frame Buffer are all completed in the UI thread. At this time, if the GPU can draw and render the graphics in different threads, the drawing will be more smooth.

RenderNode and RenderThread were introduced after Android 5.0. Their roles are as follows:

  • RenderNode: Further encapsulates Display and some View properties.
  • RenderThread: A rendering thread responsible for executing all OpenGl commands. RenderNode holds all information about the render frame and ensures smooth animation if the main thread has time-consuming operations.

After the CPU synchronizes data to the GPU, it usually does not block and wait for the RenderThread to finish rendering the view using the GPU, but instead returns after notification. The entire display call flow diagram after adding ReaderThread is shown below:

Hardware acceleration works by converting graphics computations that cpus aren’t good at into gPU-specific instructions.

1. The OpenGl API calls and Graphic Buffer buffers will occupy at least a few MB of memory, which consumes a lot of memory.

2, Some OpenGl drawing API is not supported, especially the lower version of Android system, and because each version of Android will carry out some reconstruction of the rendering module, resulting in some unpredictable bugs in the process of hardware accelerated drawing. For example, the libhwui. So crash on Android 5.0~7.0 models requires inline Hook, GOT Hook and other native debugging methods to locate the problem. The possible cause is that the ReaderThread and UI thread sync process error. This situation is usually caused by multiple views being drawn, such as View reuse and multiple animations being played at the same time.

5. Refresh mechanism

VSync signal is sent at 16ms to trigger UI rendering. The screen refresh frequency of most Android devices is 60HZ. If the rendering process cannot be completed within 16ms, frames will drop.

Screen adaptation

1. The most original Android adaptation scheme: DP + adaptive layout or weight proportional layout

First, let’s review the concepts of PX, DP, DPI, PPI, density and so on:

  • Px: pixels, px = density * dp.
  • Ppi: Pixel density, number of pixels per inch contained, screen physical parameters, non-adjustable, DPI without manual adjustment = PPI.
  • Dpi: pixel density, the number of pixels per unit size specified on the system software, which can be manually adjusted. Dpi without manual adjustment = PPI.
  • Dp: Density independent-pixels is an abstract unit based on the physical resolution of the screen. The dp control represents different real pixels on mobile phones of different resolutions and sizes. For example, in low resolution mobile phones, the dp control represents different real pixels. Maybe 1dp= 1px, or maybe 1DP =2px on a higher-resolution phone, so that a 6464DP control will look the same on different phones, px = dp (dpi / 160).
  • Denstiy: Density, the number of pixels per square inch on the screen, density = dpi / 160.

Generally, we can solve the fragmentation problem by using DP + adaptive layout (AutoLayout, ConstraintLayout, etc.) or weight proportional layout. Of course, there are some problems with this method. For example, the difference between DPI and PPI can lead to different control sizes on the same resolution phone.

2. Width and height qualifier adaptation scheme

It takes the width and height pixel values of all Android phones on the market, sets a benchmark resolution, and calculates other resolutions according to this benchmark resolution. In folders of different sizes, write corresponding Dimens files according to this size, as shown in the figure below:

For example, using 480×320 as the base resolution:

  • The width is 320, and the width of any resolution is rounded into 320 parts, ranging from X1 to x320.
  • The height is 480. The height of any resolution is rounded into 480 parts, and the value is Y1-Y480.

So for dimens files with 800*480 resolution:

  • X1 = (480/320) * 1 = 1.5 px
  • x2=(480/320)*2=3px

At this point, if the UI design interface uses the benchmark resolution, we can fill in the corresponding Dimens to reference according to the size on the design draft. When the APP runs on mobile phones with different resolutions, the system will find the corresponding value under the folder corresponding to the reference resolution according to these Dimens. However, one drawback of this solution is that there is no backward compatibility to use smaller Dimens. For example, 800×480 phones must find the 800×480 qualifier, otherwise they will have to use the default dimens file.

3, UI adaptation framework AndroidAutoLayout adaptation scheme

Inspired by the width and height qualifier scheme, Hongshen has produced a project that can use UI adaptation to develop more efficiently and adapt accurately.

The project address

4. SmallestWidth adaptation scheme (SW qualifier adaptation)

SmallestWidth is the minimum width. The system will match values- SWDP based on the minimum screen width of the current device.

As we all know, mobile devices allow the screen to rotate, and when the screen rotates, the height and width of the screen are switched, plus the word “minimum”, because this scheme does not distinguish screen orientation, it only considers the screen with the smallest median height and width as the minimum width.

And it is the same as width and height qualifier adaptation principle, the system uses specific rules to select the corresponding file. Like AndroidAutoLayout, it also addresses the issue of dimens not being backward compatible. If the screen has a minimum width of 360DP, but the project does not have a values-sw360DP folder, it will probably find values-SW320dp. Its size rule is named as shown below:

If the pixel width of our design draft is 375, then the corresponding values-SW360DP and values-SW400DP widths are as follows:

The adaptation mechanism of smallestWidth is guaranteed by the system. We only need to generate the corresponding resource file for this set of rules. Even if the corresponding smallestWidth value does not find the exact corresponding resource file, it can also be backward compatible to find the closest resource file. Although multiple DIMens files can lead to larger APK, the increase in apK size is only in the 300KB-800KB range, which is acceptable. The only variable in this scheme is the selection of which files need to be adapted with the minimum width qualifier. If you generate values- SWDP that is not too different from the actual minimum width of the device, the error is within the acceptable range; if it is too different, the effect will be poor. Finally, summarize the advantages and disadvantages of this scheme:

Advantages:

1, stable and no performance loss.

2. You can control the fit range by selecting which minimum width qualifier files are required.

3. On the basis of the plug-in that automatically generates values-SW, the learning cost is low.

The plugin address is the project code that automatically generates values-sw. The steps to generate the required values-SWdp folder are as follows:

1. Clone the project to the local PC and open it as an Android project.

2. The DimenTypes file will write the sw size you want to adapt. By default, these sizes will cover almost all mobile phone adaptation requirements.

3. The DimenGenerator file is filled with the dimensions of the design (DESIGN_WIDTH is the width of the design and DESIGN_HEIGHT is the height).

4. Execute the dimengenerator.main () method in the lib Module and the adaptor files are generated under the current address and the corresponding files and folders are copied into the project you are developing.

Disadvantages:

1. It is highly intrusive, and a large number of DIMens references need to be modified for subsequent switch to other screen adaptation schemes.

2. Models that cover more different screens need to generate more resource files, making the APK larger.

3, can not automatically support the adaptation of vertical and horizontal screen switch, if you want to support the use of values- WDP or screen direction qualifier to regenerate a set of resource files, and make the APK volume larger.

What if you want the screen width to change as the screen rotates?

Create a set of resource files according to values-wdp (drop the s in sw).

What if you want to differentiate the orientation of the screen for adaptation?

To generate a set of resource files based on the screen orientation qualifier, add the suffix -land or -port, for example: values-sw360dP-land (minimum width 360dp horizontal), values-sw400dP-port (minimum width 720 DP vertical).

Note:

If the UI design is obviously more suitable for wrap_content,match_parent,layout_weight, etc., we should not hesitate to use them. After all, these are only for situations where we have to use fixed width and height. I believe that most developers have the basic knowledge of UI adaptation.

5. Toutiao adaptation scheme

Its principle is to dynamically adjust the density of each device according to the width or height of the screen (how many pixels each DP takes up on the current device screen). By modifying the density value, the width DP value of all mobile phones with different sizes and resolutions can be changed to a unified value, so that all the adaptation problems can be solved. The corresponding important formula is as follows:

Total screen width (in pixels)/total design width (in dp) = densityCopy the code

The default project can only be high or wide as a benchmark for adaptation, not like AndroidAutoLayout, high as a benchmark, wide as a benchmark, to adapt at the same time, why?

Because, most Android devices on the market in China now have inconsistent aspect ratio of the screen, especially the current full screen, fringe screen, flexible folding screen, which makes this problem more serious, mobile phones launched by different manufacturers may have inconsistent aspect ratio of the screen. Therefore, we can only adapt based on either height or width to avoid layout distortion on screens with inconsistent aspect ratios.

It has the following advantages:

1, the use of low cost, simple operation, after the use of the scheme in the page layout does not need additional code and operation.

2, low invasive, and project complete decoupling, in the project layout does not rely on a single line of code of the scheme, and the use of or official Android API, means that when you meet any problem cannot be solved, want to switch to other screen adaptation scheme, basic don’t need to change the code before, the switching process is almost completed in an instant, The cost of trial and error is close to zero.

3, can be adapted to third-party library controls and system controls (not only activities and fragments, Dialog, Toast and other system controls can be adapted), because the modified density is global in the whole project, so as long as a modification, all places in the project will benefit.

4, there will be no performance loss.

5. No private API involved.

Its disadvantages are as follows:

1. The scope of adaptation is not controllable, and the whole project can only be adapted with one knife. There will be problems with the adaptation scheme that all controls are forced to use the size of the design drawing of our project: When the size of the design drawing of a system control or tripartite library control is larger than that of our own project, the adaptation effect of the system control or tripartite library control is worse. A better solution is to cancel the adaptation effect of the current Activity by Activity and use another adaptation solution.

2. The UI adaptation and compatibility of the old project are not enough.

Note:

Do not use the smallestWidth adaptation scheme to directly fill in the px value marked on the design drawing. This will make the project strongly coupled to this scheme, and you will have to change all layout files in the subsequent switch to other schemes.

I recommend the AndroidAutoSize project of JessYanCoding as follows:

Build. Gradle > build. Gradle > build. Gradle > build. Gradle

implementation 'me. Jessyan: autosize: 1.1.2'
Copy the code

2, then fill in the global design drawing size (unit DP) in the AndroidManifest. If you use the sub-unit, you can directly fill in the pixel size without converting the pixel to DP:

<manifest>
    <application>            
        <meta-data
            android:name="design_width_in_dp"
            android:value="360"/>
        <meta-data
            android:name="design_height_in_dp"
            android:value="640"/>           
    </application>           
</manifest>
Copy the code

Why do you just need to fill in the meta-data tag in androidmanifest.xml to automate it?

When the App starts, the declared ContentProvider is automatically instantiated in the main process of the App and its onCreate method is called before Application#onCreate to do some initialization. At this point we can start the framework with its onCreate method. If the project uses multiple processes, calling the following ContentProvider#query in Application#onCreate will instantiate it in the current process using the ContentProvider.

summary

None of the solutions described above is perfect, but we can clearly recognize the strengths and weaknesses of different solutions, and combine their strengths to meet more complex development requirements and create the best products. For example, the SmallestWidth qualifier adaptation scheme is featured by stability, and there will be few security risks in the operation process, and the adaptation range is controllable, without other unknown effects. The toutiao adaptation scheme is featured by reducing development cost, improving development efficiency, being more flexible in use, and meeting more expansion needs. Therefore, according to the specific situation, which screen adaptation plan to choose should be based on the needs of our project.

Performance analysis tool

Commonly used Performance optimization tools on Android are as follows:

  • Hierarchy View: Views the Layout Hierarchy
  • Profile tools come with Android Studio
  • Lint, the static code checking tool
  • TraceView
  • Systrace

1.1. Card detection tool Profile GPU Rendering

It is an auxiliary tool that comes with Android phones. When you open Profile GPU Rendering, you can see the color map refreshed in real time, where each vertical line represents a frame and is composed of multiple colors. The explanation of different colors is as follows:

Each bar chart is composed of red, yellow, blue, and purple, corresponding to the actual time spent in different phases of each frame.

  • Blue: Measures how long it takes to draw and how long it takes to create and update the DisplayList. When the blue line is high, it may be because it needs to be redrawn or because the onDraw function of the custom view is doing too much work.
  • Red: The execution time of Android’s 2D rendering Display List. When the red line is very high, it may be due to resubmitting the view.
  • Orange: Where the processing time or CPU tells the GPU to render a frame, if the bar graph is high, it means the GPU is too busy.
  • Purple: time to transfer resources to the rendering thread. (Available in version 4.0 and above)

In addition, from Android M, there are eight steps for rendering: 1. Orange-swap Buffers indicate the time of GPU processing tasks.

2. Red-command Issue Time for 2D rendering display list, the higher it is, the more views need to be drawn.

3. Light blue -Sync&Upload the time spent preparing the pictures to be drawn. The higher the time, the larger the number of pictures or the larger the pictures.

4, Deep blue-DRAW measures and draws the view required time, the higher the view more or onDraw method time-consuming operation.

Level 1 green -Measure/Layout Time spent by onMeasure and onLayout.

6. The time spent by the second-level green-animation to execute the Animation. A higher value indicates that an unofficial animation tool is being used or that there are reads and writes in the execution.

7. Tertiary Green-input Handling Time spent by the system to process Input events.

Misc Time/Vsync Delay The main thread performed too many tasks, resulting in UI rendering unable to keep up with Vsync signal and frame drop.

In addition, the specific elapsed time can be analyzed by exporting it to the log using the following ADB command:

adb shell dumpsys gfxinfo PACKAGE_NAME
Copy the code

Dumpsys is an Android tool that runs on devices and outputs information about the state of system services. Passing the gfXinfo command to Dumpsys provides output in logcat that records the animation that took place during each phase as well as the frame-related performance information.

Method of use

1.2, TraceView

It is mainly used to analyze the function call process, can be the Android application and Framework layer code performance analysis.

Use TraceView to check the elapsed Time, focusing on the values of Calls + Recur Calls/Total and (number of Calls to the method + recursion) and Cpu Time/Call (Time to the method), and then optimize the logic and number of Calls to these methods to reduce elapsed Time.

Note: The actual execution Time of RealTime is longer than CPU Time because it includes CPU context switching, blocking, GC, etc.

1.3, Systrace

Systrace is a performance data sampling and analysis tool provided by Android 4.1 and later. It has the following functions:

  • Collect running information about key Android subsystems (such as SurfaceFlinger, WindowManagerService and other key Framework modules, services, and View system) to analyze system bottlenecks and improve performance.
  • Track system I/0 operation, kernel work queue, CPU load, etc., provide good data on UI display performance analysis, especially on issues such as poor animation playback, render card, etc.

Note: Systrace returns some information from the system’s point of view and cannot locate specific time-consuming methods. It is recommended to use TraceView.

1. Use of Systrace

Instructions for use are as follows:

Support version 4.1 or later. 4.3 For earlier versions, open Setting>Developer Options >Monitoring>Enable traces. Normally we use the command line to get the output HTML form, but in version 4.3 and above we can omit the tracking category tag to get the default values. The command is as follows:

cd android-sdk/platform-tools/systrace
python systrace.py --time=10 -o mynewtrace.html sched gfx view wm
Copy the code

The common parameter commands are as follows:

-o: indicates the name of the file to save. -t N, – time=N: indicates the number of seconds in which data is generated. The default value is 5s. See here for the rest of the label usage.

In addition, we can use code staking. On Android 4.3 and above, we can Trace using the trace.beginSection () and trace.endSection () methods of the Trace class. Note:

  • Make sure the number of beginSection and endSection calls match.
  • Begin and end of the Trace must be executed in the same thread.
2. Analyze Systrace reports

After using Chrome to open the file, the two data most closely related to UI drawing are Alerts and Frame:

  • Alerts: Indicates a point with a performance problem. You can click this point to view the details. The Alerts box on the right also shows the number of Alerts for each type.
  • Frame: Each application has a row dedicated to Frame, and each Frame is shown as a green circle. When shown as yellow or red, it takes over 16.6ms to render. Here’s a list of useful keyboard shortcuts for Systrace:

W: Zoom in S: zoom out A: move left D: Move right

First, select our current application process in the left column. Under the application process column, there is a column of Frames. We can see three different small circles, green, yellow and red, as shown in the picture below:

Each small circle in the figure represents the state of the current frame, and the corresponding relationship is roughly as follows:

  • Normal: green.
  • Frame loss: yellow.
  • Serious frame loss: red.

In addition, if we select a frame, we can also see the corresponding Alerts alarm information in the details box at the bottom of the view to help us troubleshoot problems. In addition, for Android devices greater than or equal to 5.0 (i.e. API Level21), the work of creating frames is split between the UI thread and the Render thread. In versions of Android prior to 5.0, all the work of creating frames was done on the UI thread. Next, let’s look at the detail diagram corresponding to this frame, as shown below:

Corresponding to this frame, we found that there may be two drawing problems: too large Bitmap and too many nesting levels of layout lead to too many measures and layouts. Therefore, we need to find the corresponding Bitmap of this frame in the project for corresponding optimization, and select a more efficient layout method for the problem of too many nesting levels of layout.

In addition, the display interface of Systrace also provides an Alert box in the right sidebar to display all possible drawing performance problems detected by Systrace and the corresponding number, as shown in the following figure:

In this case, we can think of the Alert box as a list of bugs that need to be fixed, and usually improvements in one area can eliminate this type of Alert in all classes in the application, so don’t worry about the number of alerts here.

Usage Usage

Layout optimization