Android performance optimization series - UI optimization

As for most Android developers, they spend a lot of time building interfaces, writing business, and doing optimization.

When writing our interface and business, UI optimization will be crucial. Because when your UI code is poorly written, it will cause lags, frame drops, etc. (there are many reasons for lags, and UI is just one of them).

Most of the factors that affect the user experience, such as freezing and frame loss of Android applications, are related to the value of 16ms. The refresh rate of Android devices is also 60Hz. The Android system sends out a VSYNC signal every 16ms to trigger the rendering of the UI. If it exceeds 16ms, we think that a freeze has occurred.

The Android side display principle can be described in one sentence: the Android application calls the SurfaceFlinger service to render the measured, laid out and drawn Surface onto the display screen.

1. Optimization direction

1. Layout code

In our actual development, layout code is often implemented through xml and some custom controls.

Then when we write the layout code XML, we can optimize in some directions

  • Avoid over-drawing and reduce layout levels ;
    • Sometimes, there are too many controls on an interface. If you only use linear layout and relative layout, many levels will be nested to achieve drawing. In this way, the drawing level is too high. You can use relative layout to constrain the position of each control and reduce the level. If it is a simple layout, can it be implemented directly using FrameLayout, LinearLayout, etc.
  • Remove useless background and resources;
    • Overdrawing means that the same pixel is drawn multiple times when drawing the interface, but the user can only see the top-level drawn content. Therefore, can the useless background be removed, and can the picture be used without preset picture resources? , whether the textview copy can be left unset first. Remove useless parent nodes and child nodes
  • Avoid View overlap;

    • Use  canvas.clipRect()方法实现only the visible part to avoid over-drawing problems caused by View overlap. For example, when displaying a handful of playing cards, only the numbers on the left need to be displayed, so using this method, the invisible part will not Will draw.

  • Use appropriate controls;
    • In the project, you can use appropriate controls according to the project scenario, such as
      • ViewStub is a control that can be used for performance optimization. It is an invisible, zero-size View that can lazily load a layout file at runtime, thereby increasing the display rate.

        Viewstub and include are similar. They both embed another layout file in one layout file. However, viewstub can be loaded lazily. It will only load the layout file when loading is manually specified, while include will load it immediately.

        Therefore, layouts that do not have to be displayed can be replaced by ViewStub, which can reduce resource consumption when the interface is first loaded and improve the initial loading speed. For example, when there is no data or a network error, and a layout needs to be displayed separately, ViewStub can be used for this layout. ,

      • Use merge ; the redundancy of the view hierarchy can be eliminated through merge; the merge tag must be used in the root layout; tips: The attributes set for the merge tag are invalid.

  • Use some asynchronous loading framework;

Avoid View overlapping implementation code;

// 老办法
protected void onDraw(Canvas canvas) {
	super.onDraw(canvas);
	if (mDroids.length > 0 && mDroids.size() == mDroids.length) {
		for (int i = 0; i < mDroidCards.size(); i++) {
			// 每一张卡牌平移的位置
			mCardLeft = i * mCardSpacing;
			// 绘制整张卡牌 
			drawDroidCard(canvas, mDroidCards.get(i), mCardLeft, 0);
		}
	}
}

// 优化后
protected void onDraw(Canvas canvas) {
	super.onDraw(canvas);
	if (mDroids.length > 0 && mDroids.size() == mDroids.length) {
		int i;
		for (int i = 0; i < mDroidCards.size() - 1; i++) {
			mCardLeft = i * mCardSpacing;

			canvas.save();
			// 只绘制截取卡牌可见部分
			canvas.clipRect(mCardLeft, 
							0, 
							mCardLeft + mCardSpacing, 	
							mDroidCards.get(i).getHeight());
			drawDroidCard(canvas, mDroidCards.get(i), mCardLeft, 0);
			canvas.restore();
		}
		// 绘制最后一张完全可见的卡牌
		drawDroidCard(canvas, mDroidCards.get(mDroidCards.size() - 1),
			mCardLeft + mCardSpacing, 0);
	}
}

How to check if it is overdrawn?

  • Through the data cable developer mode, use the developer settings on the Android side - debug GPU overdrawing , select the display overdrawing area, and then you can see the drawing situation of the screen, among which we can see four colors, namely: blue , green, light red and red.
  • Use LayoutInspector ; LayoutInspector is a layout inspector in Android Studio, which can be found through Tools > Layout Inspector. It can check the view structure of a certain interface in the application, but it cannot view the application in a non-debug state.
  • Using the Android optimization tool Systrace is more complicated to use, but more comprehensive and specific. For specific usage, see the linked article  Android Optimization Tool Systrace - Brief Book

 2. Customize View code

        Custom Views are very common in development. When you need to implement a more complex view, it is easy to miss many details.

common problem:

  1. The onDraw method is too time-consuming;
  2. Frequent GC in onDraw method; for example, I was stupid once and put the initialization of paint and path objects in onDraw. This is very unreasonable because new objects will be created every time I draw. It can be defined directly in the class class, and just reset it when it needs to be reset.
  3. There are too many animations executed, so it is important to choose the appropriate animation. When an animation is too complex and gaudy, just ask the UI to make a lottie animation for use.
  4. Whether time-consuming operations are performed on the UI main thread.
  5. There is a memory leak; if there are static variables in the code, should they be left blank, should the animation be paused and destroyed when ondestroy is called, should the resources be closed for recycling, etc.

Guess you like

Origin blog.csdn.net/LoveFHM/article/details/135438515