preface
- Performance optimization strategies are important in Android development. Because I think prevention is always more important than cure. We should not wait until a problem has happened and reach a certain level before we think of the need to reconstruct the code or conduct performance optimization. By learning the thinking and tools of performance optimization early, we can avoid many problems and correct some bad coding habits, which is of great significance to the improvement of Coder’s coding ability.
- This article mainly explains layout optimization, hope to help you
directory
1. Impact on performance
The main impact is the speed of page display in Android applications. A page is completed through recursive measurement & drawing process = measure, layout process, and this process is too long will bring the user a slow visual effect.
2. Optimize your thinking
The idea behind layout optimization is to minimize the level of layout files. There are fewer layers of layout, which means less work for Android to draw, which results in better application performance.
3. Specific optimization plan
3.1 Remove useless controls and layers from the layout
3.2 Select a layout that requires less performance
If you can use either a LinearLayout or a RelativeLayout in your layout, use the LinearLayout. The Linearlayout uses different measurement methods based on the orientation we set. Note that if the subview of the LinearLayout uses the layout_weight attribute, you also need to measure the subview twice to determine the final size. LinearLayout and FrameLayout are both low-performance layouts. But in many cases, the effect of the product cannot be achieved simply by a LinearLayout or FrameLayout, and it needs to be completed by nesting. RelativeLayout is recommended in this case, because nesting increases the level of layout and also reduces performance.
Constraintlayout, Constraintlayout, Constraintlayout Constraintlayout is actually simpler and takes less time to draw for layouts with higher complexity (which is nested multiple times than RelativeLayout and LinearLayout). But for less complex layouts, RelativeLayout is several times faster than ConstraintLayout in the onMesaure phase. The following is the test result of the Hierarchy Viewer (with a TextView and an ImageView, the use of the Hierarchy Viewer will be described in the layout tuning tool below) :
- Low performance cost layout = simple function = FrameLayout, LinearLayout
- High-performance layout = Functional complexity = RelativeLayout (ConstraintLayout)
- Performance cost of nesting > performance cost of the individual layout itself
3.3 Improve layout reuse (using <include> layout tags)
Use <include> tags to extract common parts between layouts, reducing measurement-drawing time by increasing layout reusability
<! -- Extracted public layout :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> <! -- Layout :activity_main.xl references the public layout 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>
Copy the code
The <include> tag only supports attributes that start with Android :layout_ (except android: ID). Note that if you use android:layout_*, Android :layout_width and Android :layout_height must exist otherwise other android:layout_* attributes will not take effect. Here is an example that specifies android:layout_* attributes
<include
android:id="@+id/include_title"
android:layout_width="match_parent"
android:layout_height="48dp"
layout="@layout/include_title"/>
Copy the code
3.4 Reducing layout levels (using the < Merge > layout tag)
The <merge> layout tag is usually used with the <include> tag to reduce the hierarchy of the layout. For example, the current layout is a vertical LinearLayout. This time, if the included layout also uses a vertical LinearLayout, then obviously the LinearLayout in the included layout file is redundant. Use the <merge> layout tag to remove the extra layer of LinearLayout. As follows:
<! -- Extracted public layout :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> <! -- Layout :activity_main.xl references the public layout 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>
Copy the code
3.5 Reduce the initial measurement & drawing time
3.5.1 Using the <ViewStub> tag
The ViewStub inherits the View. It is very lightweight and has zero width and height, so it does not participate in any drawing process itself, avoids wasting resources, reduces rendering time, and loads the View only when needed. So ViewStub significance is according to the requirements of the layout of the load required, in the actual development, a lot of layout in normal circumstances will not display, such as load data temporarily no data, network anomalies such as interface, this time is not necessary at the time of the whole interface initialization loads it in, through the ViewStub can be done when use in loading, Improved program initialization performance. Here is an example of a 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="No data at present"/> </LinearLayout> <! -- Layout 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 is the ID of the ViewStub, empty is the ID of the root element of the layout empty_data. XML <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); // Load the layout in the ViewStub in two wayssetVisibility or inflate mViewStub. SetVisibility (the VISIBLE). mViewStub.inflate(); }Copy the code
Note that the ViewStub is no longer part of the layout structure when it is loaded using the setVisibility or inflate method and replaced by its internal layout. Currently, the ViewStub layout does not support the merge> tag.
3.5.2 Use wrAP_content as little as possible
The layout attribute WRAP_content increases the computational cost of layout measurements and should be used as little as possible
3.6 Reduce control use (use control properties well)
In some cases, we can dispense with the use of controls in drawing layouts. Here are some common cases:
3.6.1 TextView Text plus picture
<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"// Set the icon android:drawablePadding= displayed on the left"10dp"// Set the spacing between icon and text android:drawableRight="@mipmap/icon_right"// Set the icon android:text= displayed on the right"@string/account_unlock"
/>
Copy the code
3.6.2 LinearLayout secant lines
<? 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>
Copy the code
The core code is to set the Divider on the LinearLayout
- Divider sets the divider pattern. Note that you cannot simply assign a color value to the divider, such as #f00 or @color/ XXX. The divider can also use a drawable that defines the length and width of the divider.
- DividerPadding Sets the distance between the two sides of the dividing line
- ShowDividers Sets the location of the dividing line. Display between middle controls; Beginning shows the dividing line above the first control; End displays a divider below the last control, none does not
3.6.3 Line spacing of TextView and use of placeholders
<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"/>
Copy the code
Set the line spacing with lineSpacingExtra, test_text:
<string name="test_text"> Title: %1$s\n Time: %2$s\n Content: %3$s</string>
Copy the code
Use in MainActivity
mText.setText(String.format(getResources().getString(R.string.test_text), "Test"."2018-8-9"."Test test"));
Copy the code
How to use placeholders: %n indicates the NTH bit to be replaced, $s indicates the string type placeholder, $d indicates the integer type placeholder, and $f indicates the floating point type placeholder
4. Layout tuning tools
In the actual development, even if the above optimization scheme is paid attention to, there will inevitably be layout performance problems. At this point we can use layout tuning tools to analyze the problem. This article describes several tools that are commonly used.
4.1 Lint
Lint is a code scan analysis tool provided by Android Studio that can help us find structure/quality problems and provide solutions without requiring us to write test cases by hand. Lint is used in: Toolbar -> Analyze -> Inspect Code
The default is to check the entire project. You can customize the scope by clicking on Custom Scope
- Project Files: All Project Files
- Project Production Files: code Files for a Project
- Project Test Files: Test Files of the Project
- OpenFiles: OpenFiles
- Module ‘app’ : Main app Module
- Current File: indicates the Current File
Of course, you can also select a specific class to check by clicking the red arrow in the image below
Click “+” to add a check area:
- Local: This parameter can be used only for the current project
- Shared: Other Android Studio projects are also available
- Include: includes files in the current folder, but does not Include its subfolders
- Include Recursively added folders in your current field or in any of its subfields
- Exclude: Removes the current folder, excluding subfolders
- Exclude recurshrink: Remove the current folder and all subfolders
We left click 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
After a while, the Inspection dialog box will pop up, showing the Inspection result.
Lint warnings have the following severity:
- Unused Entry: An Unused attribute. It is grey and unimpressive
- Typo: Misspelled, wavy green, and unremarkable
- Server Problem: Server error? I don’t think so
- Info: Comment document, green and conspicuous
- Weak Warning: Weak Warning
- -Blair: I’m Warning you
- ErrorError, the most obvious one
That’s all you need to know about Lint in this article. You can click Lint if you want to learn more about Lint
4.2 Hierarchy Viewer
Hierarchy Viewer is a UI performance monitoring tool provided by Android Studio. Get UI layout design structure & various attribute information to help us optimize layout design.
To use the Hierarchy Viewer, your device must be running Android 4.1 or higher. Note the following two points if you are using a real machine:
- Enable developer options on your device.
- Set the environment variable ANDROID_HVPROTO= DDM on the development machine. This variable tells Hierarchy Viewer to connect to the device using the DDM protocol, which is the same as the DDMS protocol. 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 the Hierarchy Viewer.
Hierarchy Viewer usage path: You can click Open Perspective->Hierarchy Viewer to change the DDMS window. You can also directly click the Hierarchy Viewer Button, as shown below:
The window for displaying Hierarchy Viewer after modification is as follows:
If you are looking at different views, select Window->Reset Perspective to return the default layout. Here are the basic Windows:
- Window (upper left corner) displays device information, app is displayed by package name, double-click select.
- View Properties (upper left corner) Displays the Properties of the View
- Tree View (Center) : Displays a Tree View of 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 (top right) : Gives you a bird ‘s-eye view of the complete view hierarchy of the application. Move the gray rectangle to change the viewport visible in the tree view.
- Layout View(Bottom right) : Shows a wireframed view of the layout. The outline of the currently selected view is red and its parent view is light red. The view that you click here will also be inIn the tree viewChoose it and vice versa.
Left to right:
- Reload the view hierarchy
- The view pops up
- Invalidate the layout
- Request the layout
- Reload the view hierarchy
- Analyze a view and display the view time
Measure
Layout
Draw
- The left dot represents the rendering process of the render pipe.
- The middle point represents the layout stage.
- The right dot indicates the execution phase.
These points roughly correspond to the measurement, layout, and drawing phases of the processing pipeline. The color of the dot indicates the relative performance of this node relative to all other configured nodes in the local family.
- Green means that the view renders at least half as fast as the other views.
- Yellow indicates that the view renders faster than the lower half of other views.
- Red indicates that the view is one of the slowest half views.
What is measured is the performance of each node relative to its 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 badly (only if it is the slowest view) in the local view group.
This article concludes the introduction to the Hierarchy Viewer. For more information, click on the Hierarchy Viewer
4.3 Developer Options (Debug GPU overdrawing)
Developer option is an entry for APP verification, debugging, optimization and other functions provided by Android system for developers (above Android 4.1). This article mainly introduces the menu drawn by GPU. Interested in other menu functions, you can refer to explore Android phone developer options
GPU overdrawing refers to that a pixel on the screen is drawn many times within the same frame. There are two main reasons for this:
- In AN XML layout, controls overlap but all set backgrounds
- View’s OnDraw draws the same area multiple times
4.3.1 Enabling the Developer option
Different mobile developers have customised the interface, opening developer options in different ways, but the basic menu of features is similar. As the author is now using Mi 5S Plus, the opening method is Settings -> My Device -> All Parameters -> continuously click MIUI version and prompt developer mode to open (the opening path is different for different MIUI versions). Then go to Settings -> More Settings, Advanced Settings or other Settings to see the developer options menu.
4.3.2 Enabling GPU Overdrawing
Click Debug GPU Overdraw in developer options, as shown below
A variety of colors will appear on the screen. Each color is defined as:
- Primary colors: No overpainting – each pixel is painted once on the screen.
- Blue: One overdraw – each pixel is drawn twice on the screen.
- Green: Two overdraws – each pixel has been drawn three times on the screen.
- Pink: Three overdraws – each pixel is painted on the screen four times.
- Red: Four or more overdraws – each pixel has been painted five or more times on the screen.
These are the layout tuning tools introduced in this article, but there are other layout tuning tools such as Systrace that are not covered in this article.
At the end
This article focuses on layout optimization in Android performance optimization. If be helpful to small friends, trouble give a like, insufficient place please leave a message private chat point out thank you! For those interested in Flutter, see the path to Flutter Learning (1) Introduction to Flutter and Window development environment