Performance Optimization for Android Development: Transition Drawing Solution

1. Transition drawing

A certain pixel on the screen is repeatedly drawn multiple times in one frame, which is transitional drawing.
The image below shows multiple cards falling together, but only the first card is fully visible. The cards behind are only partially visible. However, the Android system will draw the lower cards when drawing, and then draw the upper cards. But in fact, the invisible part of the lower card does not need to be drawn, only the visible part needs to be drawn.

According to the level of transition drawing, it can be divided into:

  • Draw without transitions (a pixel is drawn only once)
  • transition draw x1 (a pixel is drawn twice)
  • transition draw x2 (a pixel is drawn three times)
  • Overdraw x3 (a pixel is drawn four times)
  • Overdraw x4+ (a pixel is drawn more than five times)

2. View the transition drawing of your application

Method 1: Enable GPU transition rendering debugging through developer options

In the developer options of the Android phone, there is an option of "debug GPU overdrawing":

After clicking on it, select "Show Transition Drawing Area":

Method 2: Enable GPU transition rendering debugging through the adb command

Of course, if it is troublesome to enter the system settings every time, you can use the adb command to turn it on and off:
turn on "Debug GPU overdrawing":

adb shell setprop debug.hwui.overdraw show

Turn off "Debug GPU Overdraw":

adb shell setprop debug.hwui.overdraw false

It may be necessary to restart the application you are currently developing after executing the command.

Color and transition drawing:

  • Primary colors: no overdraw
  • Blue: 1 overdraw
  • Green: 2 overdraws
  • Pink: 3 overdraws
  • Red: 4 or more overdraws

In normal development, if there is a transition drawing situation of pink and above. Instructions for overdrawing are pretty severe as well. Needs to be optimized.

3. Optimize transition drawing

1. Remove the default background color that comes with the Activity:

View the Theme theme in the Android source code, as follows:

<style name="Theme">
    ...
    <!-- Window attributes -->
    <item name="windowBackground">@drawable/screen_background_selector_dark</item>
    ...
</style>

That is to say, inheriting the style of Theme, by default, creating a new Activity has a background. Under normal circumstances, many interfaces do not actually need a background.

The following is the homepage of Huawei's built-in weather app. We can see that the text and icons are green. The surface is already drawn on the third layer of transition. The weather map behind it is a layer, and the text is another layer. It is normal. It is said that there should be only two layers, that is, the text and icons should be blue.

Then this extra layer should be the background color that comes with the Activity. That is set in the theme.

We just need to remove the background color in our AppTheme:

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

Or in the Activity's onCreate method:

getWindow().setBackgroundDrawable(null);

2. Use the clipRect and clipPath methods of Canvas to limit the drawing area of ​​View

An Activity corresponds to a Canvas, which is the canvas. The concept of the canvas is a drawing board. This canvas provides many APIs. We can draw and do some operations on the canvas by calling the API of the canvas. The clipRect method is used to cut the canvas. A rectangular area of ​​, which is described by a Rect object. After calling clipRect, the drawable area of ​​the canvas is reduced to the same size as the rectangular area specified by Rect. All drawing will be limited to this rectangle. The cropping concept here is similar to that in PS.

A typical example, drawer layout, I found Netease Cloud Music to do the surgery:

image.png

Pay attention to observe that when the left drawer is opened, the drawer layout overlaps with the back layout. At this time, more than half of the entire screen turns red, and the transition drawing is serious.

When the drawer layout pops up, the drawer layout is opaque, which means that the content layout behind the drawer layout does not need to be drawn, but NetEase Cloud draws it, causing the pixels in the area where the drawer layout is located to be drawn multiple times.

Google officially has the DrawerLayout.Java class under the android.support.v4.widget package. Used to implement the drawer layout. This class overrides the drawChild method:

@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
    final int height = getHeight();
    // 判断是否是内容视图
    final boolean drawingContent = isContentView(child);
    int clipLeft = 0, clipRight = getWidth();

    // 记录当前画布信息
    final int restoreCount = canvas.save();
    if (drawingContent) {
        // 只有在绘制内容视图时才进行裁切
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View v = getChildAt(i);
            if (v == child || v.getVisibility() != VISIBLE ||
                    !hasOpaqueBackground(v) || !isDrawerView(v) ||
                    v.getHeight() < height) {
                // 如果child是内容视图/视图不可见/视图背景透明/不是抽屉视图/child高度小于父布局高度
                // 则不做画布裁切
                continue;
            }

            if (checkDrawerViewAbsoluteGravity(v, Gravity.LEFT)) {
                // 盒子在左侧时裁切的left和right
                final int vright = v.getRight();
                if (vright > clipLeft) clipLeft = vright;
            } else {
                // 盒子在右侧时裁切的的left和right
                final int vleft = v.getLeft();
                if (vleft < clipRight) clipRight = vleft;
            }
        }
        // 裁切画布
        canvas.clipRect(clipLeft, 0, clipRight, getHeight());
    }
    // 绘制子视图
    final boolean result = super.drawChild(canvas, child, drawingTime);
    // 回复到裁切之前的画布
    canvas.restoreToCount(restoreCount);
}

The drawChild method is called in the dispatchDraw method of the ViewGroup class to draw subviews. The DrawerLayout class rewrites this method because the drawChild method is called before all child views are drawn, but here only the content area view needs to be cut. When drawing the content area view, obtain the position information of the drawer view. If the drawer view is visible, the background is opaque, and the height of the drawer is consistent with the height of the parent layout, obtain the position information of the left, top, right, and bottom edges of the drawer view in the canvas. Then cut, cut out the part of the content view that is not blocked, and hand over the cut canvas to the child View for drawing, so that the content area will only be drawn in the cut area, and other areas will not be drawn. draw.

After the sub-View is drawn, restore the Canvas to the state before cutting, because all the Views under a Window use the same Canvas, so it is necessary to restore the state for other sub-Views to use.

Let's look at the "download" APP in a system, which is implemented by DrawerLayout:

Although the content area is red in the application, after the drawer view is pulled out, the transition drawing of the drawer view is less than that of the unobstructed part of the content area.

3. ImageView's background and imageDrawable overlap

In Android, all views can set the background. In addition to setting the background, ImageView can also set ImageDrawable.

In development, it is often necessary to display a picture. Before the picture is loaded, it is usually necessary to display a default picture. In many cases, the background property of ImageView is used to set the default background picture, and imageDrawable is used to set the picture to be loaded. This will cause a problem. When the image is loaded on the page, the default background image is blocked, but it still needs to be drawn, resulting in transitional drawing.

The solution is to set both the background image and the actually loaded image through the imageDrawable method.

4. Summary

  • A window in Android corresponds to a Canvas, and all views (View/ViewGroup) under the window use the same canvas, and the parent node of the view tree will cut the Canvas before calling the View.draw of the subview. The area is the rectangular area occupied by the View on the screen, which is why the content beyond the border of the View will be cut off.

  • Since one pixel of the transition drawing value is drawn multiple times, we only need to ensure that the pictures or background colors do not overlap. The correct way should be to minimize the overlapping area of ​​View with background. If it overlaps, use the clipRect of the canvas to crop.

  • Minimize the depth of the view to reduce the traversal process of the view tree.

at last

Finally, I want to say: For programmers, there are too many knowledge content and technologies to learn. If you want not to be eliminated by the environment, you have to constantly improve yourself. We have always adapted to the environment, not the environment to adapt to us. !

In order to help everyone better grasp the performance optimization in a comprehensive and clear manner, we have prepared relevant core notes (returning to the underlying logic):https://qr18.cn/FVlo89

Performance optimization core notes:https://qr18.cn/FVlo89

Startup optimization

Memory optimization

UI

optimization Network optimization

Bitmap optimization and image compression optimization : Multi-thread concurrency optimization and data transmission efficiency optimization Volume package optimizationhttps://qr18.cn/FVlo89




"Android Performance Monitoring Framework":https://qr18.cn/FVlo89

"Android Framework Study Manual":https://qr18.cn/AQpN4J

  1. Boot Init process
  2. Start the Zygote process at boot
  3. Start the SystemServer process at boot
  4. Binder driver
  5. AMS startup process
  6. The startup process of the PMS
  7. Launcher's startup process
  8. The four major components of Android
  9. Android system service - distribution process of Input event
  10. Android underlying rendering-screen refresh mechanism source code analysis
  11. Android source code analysis in practice

Guess you like

Origin blog.csdn.net/weixin_61845324/article/details/132351467