1. An overview of the

UI rendering operations typically rely on two core components: the CPU and GPU. CPU is responsible for calculation operations including Measure, Layout, Record and Execute, while GPU is responsible for Rasterization. Rasterization is the splitting of UI controls (such as buttons and bitmaps) into different pixels for display. This is a time-consuming operation, and the GPU can speed up the rasterization operation. In Android we have a 16ms guideline for smooth App flow. This is because the typical Android screen refresh rate is 60Hz, which is about 16.6ms per frame. This means that our CPU and GPU must complete all computation, drawing, and rendering operations within 16ms, otherwise there is a risk of frame drops, stuttering, performance issues, and user experience damage. Overdraw is when a pixel on a screen is drawn too many times in the same frame (16ms). Frames can be lost for a number of reasons, whether it’s because your layout is too complex to measure and layout in 16ms, whether it’s because your UI has too many drawing units stacked on top of each other, or whether it’s because the animation is executed too many times. There could be other time-consuming operations in the main thread, or too many threads. The CPU or GPU is overloaded.

2. Debug GPU transition drawing

Adb shell setprop debug.hwui. Overdraw show

Adb shell setprop debug.hwui. Overdraw false

3. Classification of over-drawing:

Primary color: No overpainting

Blue: 1 overdraw

Green: 2 overdraws

Pink: 3 overdraws (should not exceed a quarter of the screen)

Red: 4 or more overdraws (cannot occur)

4. Avoid overdrawing

4.1 Remove the Activity’s redundant background

(1) When we create a new Activity, the Activity’s Theme usually automatically has a background. But most of the time this background is unnecessary, we use our own controls often already set the background;

Change the background in the APP Theme:

<style name="AppTheme" parent="android:Theme.Light.NoTitleBar">
    <item name="android:windowBackground">@null</item>
    ...
</style>
Copy the code

(2) In many cases, the background property is already set on the root Layout of the Activity Layout file. In this case, the Activity’s own background is unnecessary.

Try the following code in the Activity’s onCreate() :

getWindow().setBackgroundDrawable(null);
Copy the code

If it’s in a Fragment, yes

getActivity().getWindow().setBackgroundDrawable(null)
Copy the code

4.2 ImageView background overlaps with setImageDrawable()

When we use ImageView and other similar controls to display images, we usually have a placeholder for the loading process. Most of the time, we use the background property to add the placeholder. After the network requests the image, we use setImageDrawable() to set the image. In this way, the image will overwrite the original placeholder, but when the Android system draws the interface, both the original placeholder and the current image will be drawn, resulting in Overdraw.

Use setImageDrawable() for placeholder and later loaded images, not background

4.3 Reduce the complex Shape of Drawable

The use of complex shapes can sometimes be a factor in overdrawing, such as Stroke, which adds a layer of overdrawing to an entire area, even though it is just a Stroke. For example, use the following configuration as the background for the ImageView.

<solid android:color="#FFF8F8F8" /> <stroke android:dashGap="4dp" android:dashWidth="2dp" android:width="2dp" android:color="#ff1111" /> <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />  <corners android:radius="6dp" />Copy the code

4.4 Flatten the view hierarchy

Modern layouts make it easier to stack and layer views. However, doing so can lead to overdrawing, which can degrade performance. Especially in scenarios where each stacked view object is opaque, both visible and invisible pixels need to be drawn on the screen.

If you encounter such problems, you can improve performance by optimizing the view hierarchy to reduce the number of overlapping UI objects.

To flatten the layout, use a ConstraintLayout.

4.5 correct use of onDraw function in custom controls

In custom controls, we often use the onDraw function to draw complex shapes, text, images, etc. However, each time these Canvas drawing functions are called, a layer of drawing will be added, and the more times they are called, the more overdrawing will occur. If we use the following code to customize the drawing, there will be a situation of drawing three times:

protected void onDraw(Canvas canvas) {
    // TODO Auto-generated method stub
    int width = getWidth();
    int height = getHeight();
    Paint paint = new Paint();
    paint.setColor(0xFFFFFFFF);
    canvas.drawColor(0xFFFFFFFF);
    canvas.drawRect(20, 20, width - 20, height - 20, paint);
    canvas.drawCircle(width / 2, height / 2, 50, paint);
    
  }
Copy the code

4.6 Merge labels to reduce View tree levels

Whenever we customize a reusable layout, we create a new file to hold the layout. When we include the layout file, we probably have an extra layer of layout. If you Merge a layout that contains this, the system automatically ignores the Merge hierarchy and places its child views directly in the same layout as the include. Another case, for example, is that the LinearLayout is embedded in a layout, and the root node of the layout is also the LinearLayout, which uses the same type of layout for the two layers. This problem can be avoided by using the merge root tag to reduce unnecessary nesting.

However, it can only be used as the root tag of the XML layout. When a layout file starts with the Inflate, you must specify a parent ViewGroup, and you must set attachToRoot to True.

4.7 Optimizing the Layout using the ViewStub tag

Interfaces that display errors, load prompts, Progressbars, and interfaces that the user rarely triggers can have a detrimental effect on Infalte performance, memory, and so on when stacked with layouts that do not have to be displayed. In this case, the ViewStub tag is appropriate. You can save these infrequently used layouts as separate layout files and use the ViewStub tag instead of the corresponding layout. Wait until you really need to display the ViewStub. Because the ViewStub is a lightweight View, it is an invisible control that takes no layout position and consumes very little resources. So with the ViewStub, you can speed up the time of the Inflate and reduce the number of objects created, thereby improving performance and reducing memory footprint. The ViewStub, however, can only be synchronized once, and once initialized that tag is replaced by the actual layout.

4.8 Reduce unwanted Views

On the one hand, reducing the hierarchy itself reduces the number of views. On the other hand, for some scenes, the text has different sizes and colors. In fact, it can be realized with a TextView, for example, it can be realized with the Spannable object. You don’t have to use a lot of TextViews to do that.

In addition, sometimes we find a blank space placeholder using a view, which can be replaced by layout_margin or other methods.