Alibaba’s first, second, and third technical aspects were all asked about Android layout optimization, and a comprehensive review of optimization ideas and optimization plans

Preface

  • In Android development, performance optimization strategies are very important. Because I think prevention is always more important than cure. We shouldn’t wait until a problem has occurred, and to a certain extent, we only remember that we need to refactor the code or perform performance optimization. Many problems can be avoided through early learning of performance optimization thinking and tools, and some bad coding habits can be corrected. The improvement of the coding ability is of great significance.
  • This article mainly explains layout optimization , I hope it will help you

table of Contents

1. Impact on performance

Mainly affect the speed of page display in Android applications . One page completes the measurement & drawing process through recursion = the process of measurement and layout, and if this process is too long, it will give users a visual effect of lag.

2. Optimization ideas

The idea of ​​layout optimization is actually very simple, which is to minimize the level of layout files. There are fewer layout levels, which means less work when Android draws, so the performance of the program is naturally higher.

3. Specific optimization plan

3.1 Delete useless controls and levels in the layout

3.2 Choose a layout that consumes less performance

If either LinearLayout or RelativeLayout can be used in the layout , then LinearLayout is used . Because RelativeLayout needs to measure the vertical and horizontal directions of the child View twice when drawing , and Linearlayout calls different measurement methods according to the direction we set when drawing. Note that if the layout_weight attribute is used for the sub-View in LinearLayout , it is also necessary to measure the sub-View twice to determine the final size (for those who do not know this, you can check the onMeasure and onLayout methods in the source code. This article will not post the source code). LinearLayout and FrameLayout are both a layout with low cost and performance. However, in many cases , the effect of the product cannot be achieved by simply using a LinearLayout or FrameLayout , and it needs to be completed by nesting. In this case, it is recommended to use RelativeLayout , because nesting is equivalent to increasing the level of the layout, which will also reduce the performance of the program.

The comments mentioned Constraintlayout many times , because the author used it less, forgot to say, neglect, neglect [manual cry and laugh]. In the face of high-complexity layouts ( multiple nesting than RelativeLayout and LinearLayout ) Constraintlayout is indeed simpler and the drawing time is shorter. But in the face of less complex layouts, RelativeLayout is several times faster than ConstraintLayout in the onMesaure stage. The following figure shows the test results of Hierarchy Viewer (there is a TextView and an ImageView. The use of Hierarchy Viewer will be in the layout tuning tool below):

  • Low-performance layout = simple function = FrameLayout, LinearLayout
  • High-performance layout = complex functions = RelativeLayout (ConstraintLayout)
  • Performance cost of nesting> Performance cost of a single layout itself

3.3 Improve the reusability of the layout (using the <include> layout tag)

Use <include> tags to extract common parts between layouts, reduce measurement & drawing time by improving the reusability of layouts

<!--抽取出的公共布局:include_title.xml-->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorAccent">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:paddingLeft="15dp"
        android:src="@mipmap/ic_titilebar_back"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="@string/title"
        android:textColor="@color/white"
        android:textSize="18sp"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:gravity="center"
        android:padding="15dp"
        android:text="@string/more"
        android:textColor="@color/white"
        android:textSize="16sp"/>

</RelativeLayout>


<!--布局:activity_main.xl引用公共布局include_title.xml-->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

     <include layout="@layout/include_title"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="Hello World!" />

</LinearLayout>

示ä¾å¾3.3

The <include> tag only supports attributes starting with android:layout_ (except android:id). Note that if android:layout_* attributes are used, then android:layout_width and android:layout_height must exist, otherwise other androids The attributes of the form :layout_* cannot take effect. The following is an example that specifies the attributes of android:layout_*

<include
    android:id="@+id/include_title"
    android:layout_width="match_parent"
    android:layout_height="48dp"
    layout="@layout/include_title"/>

3.4 Reduce the layout level (using the <merge> layout tag)

The <merge> layout tag is generally used together with the <include> tag to reduce the level of layout. For example, the current layout is a vertical LinearLayout. At this time, if the included layout also uses a vertical LinearLayout, then obviously the LinearLayout in the included layout file is redundant. In this case, use the <merge> layout tag. You can remove the extra layer of LinearLayout. As follows:

<!--抽取出的公共布局:include_title.xml-->
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />

</merge>

<!--布局:activity_main.xl引用公共布局include_title.xml-->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <include layout="@layout/include_title"/>

</LinearLayout>

示ä¾å¾3.4

3.5 Reduce initial measurement & drawing time

3.5.1 Using the <ViewStub> tag

ViewStub inherits View . It is very lightweight and has zero width and height. Therefore, it does not participate in any drawing process, avoiding waste of resources, reducing rendering time, and loading View when needed. Therefore , the meaning of ViewStub is to load the required layout as required. In actual development, many layouts will not be displayed under normal circumstances. For example, there is no data when loading data, and the network is abnormal. At this time, there is no need to initialize the entire interface. Load it in at some time, and use ViewStub to load it during use, which improves the performance of program initialization. The following is an example of ViewStub :

<!--暂无数据页:empty_data.xml-->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@mipmap/ic_empty_order"/>

    <TextView
        android:layout_below="@+id/iv_empty"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="暂无数据"/>

</LinearLayout>

<!--布局activity_main.xml-->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    //view_stub是ViewStub的id,empty是empty_data.xml这个布局根元素的id
    <ViewStub
        android:id="@+id/view_stub"            
        android:inflatedId="@+id/empty"         
        android:layout="@layout/empty_data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</LinearLayout>

<!--MainActivity-->
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        //加载ViewStub中的布局的两种方式setVisibility或inflate
        mViewStub.setVisibility(View.VISIBLE);
        mViewStub.inflate();
        
    }

示ä¾å¾3.5.1

Note when using ViewStub : When the ViewStub is loaded through the setVisibility or inflate method, the ViewStub will be replaced by its internal layout. At this time, the ViewStub is no longer a part of the layout structure. The layout in ViewStub currently does not support the use of the <merge> tag.

3.5.2 Use the layout attribute wrap_content as little as possible

The layout attribute wrap_content will increase the calculation cost during layout measurement and should be used as little as possible

3.6 Reduce the use of controls (make good use of control properties)

In drawing the layout, in some cases we can omit the use of some controls. Here are a few common situations:

3.6.1 TextView text and image
 

示ä¾å¾3.6.1

In the above layout, what usually comes to mind is that a relative layout contains a TextView and two ImageViews. In fact, we only need a TextView to achieve

<TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_marginTop="20dp"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:gravity="center_vertical"
        android:drawableLeft="@mipmap/icon_my_unlock"   // 设置左边显示的icon  
        android:drawablePadding="10dp"                  // 设置icon和文本的间距  
        android:drawableRight="@mipmap/icon_right"      // 设置右边显示的icon
        android:text="@string/account_unlock"
        />

3.6.2 LinearLayout dividing line

Example Figure 3.6.2

The layout in the above picture is usually displayed with a View with a height of 1dp. In fact, LinearLayout itself can achieve

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:divider="@drawable/divider_line"
    android:dividerPadding="16dp"
    android:showDividers="middle"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:gravity="center_vertical"
        android:drawableLeft="@mipmap/icon_my_unlock"
        android:drawablePadding="10dp"
        android:drawableRight="@mipmap/icon_right"
        android:background="@color/color_FFFFFF"
        android:text="@string/account_unlock"
        />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:gravity="center_vertical"
        android:drawableLeft="@mipmap/icon_my_unlock"
        android:drawablePadding="10dp"
        android:drawableRight="@mipmap/icon_right"
        android:background="@color/color_FFFFFF"
        android:text="@string/account_unlock"
        />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:gravity="center_vertical"
        android:drawableLeft="@mipmap/icon_my_unlock"
        android:drawablePadding="10dp"
        android:drawableRight="@mipmap/icon_right"
        android:background="@color/color_FFFFFF"
        android:text="@string/account_unlock"
        />

<!--Shape:divider_line.xml-->
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <solid android:color="@color/colorPrimary"/>
    <size android:height="1dp"/>

</shape>

</LinearLayout>

The core code is to set the divider for LinearLayout

  • The divider sets the dividing line style. Note that you cannot simply give a color value, such as #f00 or @color/xxx. The drawable must be a drawable with the concept of length and width. Of course, you can also directly use a picture as a divider.
  • dividerPadding sets the spacing on both sides of the dividing line
  • showDividers sets the display position of the dividing line. Among them are displayed between middle controls; beginning displays the dividing line above the first control; end displays the dividing line below the last control, none does not display the dividing line

3.6.3 Use of line spacing and placeholders in TextView

Example Figure 3.6.3

 

<TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:lineSpacingExtra="10dp"
        android:text="@string/test_text"
        android:textSize="20sp"
        android:textColor="@color/colorPrimary"/>

Set the line interval by lineSpacingExtra , the content of test_text is:

<string name="test_text">标题:%1$s\n时间:%2$s\n内容:%3$s</string>

Use in MainActivity

mText.setText(String.format(getResources().getString(R.string.test_text), "测试", "2018-8-9","测试测试"));

How to use placeholders: %n means the nth place to be replaced, $s means string type placeholders, $d means integer placeholders, $f means floating point placeholders

4. Layout Tuning Tool

In the actual development, even if the above optimization scheme is paid attention to, the layout performance problem will inevitably occur. At this time, we can use the layout tuning tool to analyze the problem. This article will introduce several commonly used tools.

4.1 Lint

Lint is a code scanning analysis tool provided by Android Studio. It can help us find code structure/quality problems, and provide some solutions, and this process does not require us to write test cases. Lint use path: Toolbar -> Analyze -> Inspect Code

Example Figure 4.1.1

 

The default is to inspect the entire project, we can click Custom scope to customize the inspection scope

  • Project Files: all project files
  • Project Production Files: project code files
  • Project Test Files: project test files
  • OpenFiles: currently open files
  • Module'app': the main app module
  • Current File: current file

Example Figure 4.1.2

 

Of course, you can also select a specific class to check and click on the place marked by the red arrow in the figure below

Example Figure 4.1.3

 

Click the "+" sign to add a new inspection scope:

  • Local: Only available for the current project
  • Shared: other Android Studio projects can also be used

Example Figure 4.1.4

 

Select Shared, the default is displayed by project, and the number of files checked is 0. The 4 buttons in the red box in the figure below indicate the type of operation

  • Include: include the files in the current folder, but not its subfolders
  • Include Recursively: Include all folders in the current folder and its subfolders, recursively add
  • Exclude: remove the current folder, excluding subfolders
  • Exclude Recursively: Remove the current folder and all subfolders

Example Figure 4.1.4

We left click on the file we want to scan and click the corresponding button on the right. You can see the edge color of the file, the red box shows that 24 files need to be scanned, click OK→OK

Example Figure 4.1.5

 

After a while, the Inspection dialog box will pop up, displaying the inspection results.

Example Figure 4.1.6

 

Lint's warning severity is as follows:

  • Unused Entry : unused attributes, gray, very inconspicuous
  • Typo : Spelling mistake, green wavy underline, and not very eye-catching
  • Server Problem : Server error? seems not
  • Info : Annotated documents, green, more conspicuous
  • Weak Warning : Weak warning, weaker prompt
  • Warning : Warning, slightly conspicuous
  • Error : Error, the most conspicuous oneExample Figure 4.1.7

This article's introduction to Lint is here. If you want to know more about Lint, you can click Lint

4.2 Hierarchy Viewer

Hierarchy Viewer is a UI performance testing tool provided by Android Studio. Get UI layout design structure & various attribute information to help us optimize layout design.

To use Hierarchy Viewer , your device must be running Android 4.1 or higher. If you are using a real phone, you need to pay attention to the following two points:

  • Enable developer options on your device .
  • Set the environment variable ANDROID_HVPROTO=ddm on the development computer .
    This variable tells Hierarchy Viewer to connect to the device using the ddm protocol, which is the same as the DDMS protocol. It is important to note that there can only be one process connected to the device on the host, so you must terminate any other DDMS sessions to run Hierarchy Viewer.

Hierarchy Viewer use path: Toolbar->Tools->Android->Android Device Monitor (the default is to display the DDMS window, you can change it by clicking Open Perspective->Hierarchy Viewer , or you can directly click the Hierarchy Viewer Button ), as shown in the figure below:

Example Figure 4.2.1

 

The window showing the Hierarchy Viewer after the change is as shown in the figure below:

Example Figure 4.2.2

 

If you are looking at different views, you can choose Window->Reset Perspective to return to the default layout. The following describes the basic windows:

  • Window (upper left corner) displays device information, app is displayed by package name, double click to select.
  • View Properties (top left corner) shows the properties of the view
  • Tree View (center): A tree view showing the view hierarchy. You can use the mouse to drag the tree and zoom the tree, and use the zoom control at the bottom. Each node indicates its View class name and ID name.
  • Tree Overview (upper right corner): Allows you to have a bird's eye view of the complete hierarchy of the application. Move the gray rectangle to change the viewport visible in the tree view .
  • Layout View (lower right corner): shows the wireframe view of the layout. The outline of the currently selected view is red, and its parent view is light red. Clicking on the view here will also select it in the tree view, and vice versa.Example Figure 4.2.3Example Figure 4.2.4

The use of the icons in the above figure is introduced from left to right:

  • Reload the view hierarchy
  • The view popup
  • Invalidate layout
  • Request layout
  • Reload the view hierarchy
  • Analyze the view and display the time consuming of the view

Example Figure 4.2.5

 

A small window above the selected node will display the number of child views and the time required for Measure , Layout , and Draw drawing.
Each subview of the selected node has three points, which can be green, yellow or red.

  • The left point represents the drawing process of the rendering pipeline.
  • The middle point represents the layout stage.
  • The right dot indicates the execution stage.

These points roughly correspond to the measurement, layout, and drawing stages of the processing pipeline. The color of the dot indicates the relative performance of the node relative to all other configuration nodes in the local series.

  • Green means that the view rendering speed is at least half faster than other views.
  • Yellow means that the view is rendered faster than the lower half of other views.
  • Red indicates that the view is one of the slowest half of the views.

What is measured is the performance of each node relative to the sibling view, so there is always a red node in the configuration file, unless all views perform the same, and it does not necessarily mean that the red node performs poorly (only if it is the slowest View) in the local view group).

This is the end of the introduction of Hierarchy Viewer in this article . If you want to know more, please click Hierarchy Viewer

4.3 Developer options (Debug GPU overdrawing)

Developer option is an entry for various functions such as APP verification, debugging, optimization, etc. provided by the Android system for developers (Android 4.1 or above is required). This article mainly introduces the GPU over-drawing menu. Friends who are interested in other menu functions can refer to Explore Android phone developer options

GPU overdrawing means that a certain pixel on the screen is drawn multiple times in the same frame. There are two main reasons for this:

  • In the XML layout, the controls overlap but all set the background
  • Draw the same area multiple times in OnDraw of View

4.3.1 Open developer options

Different mobile phone developers have customized the mobile interface, and the ways to open the mobile phone developer options are different, but the basic function menus are similar. Since the author is currently using Mi 5s Plus, the opening method is Settings -> My Device -> All Parameters -> Continuously click the MIUI version to prompt the developer mode to be turned on (the opening path is different for different MIUI versions). Then you can see the developer options menu in the Settings -> More Settings, Advanced Settings or Other Settings menu.

4.3.2 Turn on GPU overdraw

Click Debug GPU overdraw in the developer options, as shown in the figure below

Example Figure 4.3.2.1

 

Example Figure 4.3.2.2

 

At this time, various colors will appear on the screen, and the definition of each color is:

  • Primary colors: No overdrawing-each pixel is drawn once on the screen.
  • Blue: Overdraw once-each pixel is drawn twice on the screen.
  • Green: Overdraw twice-each pixel is drawn on the screen three times.
  • Pink: Overdraw three times-each pixel is drawn on the screen four times.
  • Red: Overdraw four or more times-each pixel is drawn on the screen five or more times.

The above is the introduction to the layout tuning tools in this article. Of course, there are other layout tuning tools such as Systrace. This article will not introduce them one by one.

end

This article mainly explains layout optimization in Android performance optimization. If it is helpful to the friends, please give me a liking. Please leave a message and private chat for the shortcomings.

Articles are continuously updated every week. You can search for "Programming Ape Cultivation Center" on WeChat to read and update as soon as possible (one or two articles earlier than the blog), and "click on the interview/more information under the official account" to get it directly for free Summary of Interview Questions for Android Development Jobs of First- and Second-tier Internet Companies (Answer Analysis) and Summary of Android Architecture Knowledge Points pdf + Ultra-clear Android Advanced Mind Map

Guess you like

Origin blog.csdn.net/qq_39477770/article/details/108641455