Android best performance practices (IV)-layout optimization skills, android Best Performance

Source: Internet
Author: User

Android best performance practices (IV)-layout optimization skills, android Best Performance

Reprinted please indicate the source: http://blog.csdn.net/guolin_blog/article/details/43376527

In the previous articles, we learned how to improve the performance of applications by managing the memory reasonably and using high-performance coding techniques. However, in fact, the interface layout will also have a great impact on the performance of the application. If the layout is poorly written, the UI loading speed of the program will be very slow, this results in poor user experience. In this article, we will learn how to optimize the layout to provide application performance. If you have not read the previous article, you can read it first.Android best performance practices (III)-high-performance coding Optimization.

Reuse layout files

Many easy-to-use controls are provided in the Android system, which makes it easy to compile the layout. However, sometimes we may need to reuse a previously written layout repeatedly. If you always use the copy and paste Method for layout reuse, this is obviously a very stupid approach. Android, of course, has fully taken into account the importance of layout reuse. Therefore, it provides two very useful labels: <include> and <merge>. Let's take a look at them one by one.

<Include>

<Include> Labels allow the introduction of another layout in one layout. For example, all interfaces of our program have a public part, the best practice at this time is to extract the public part into an independent layout file, and then reference this public layout in the layout file of each interface.

For example, we should all know that almost all software currently has a head layout, which can contain the interface title, return button, and other operation functions. Some software uses ActionBar to implement such a header layout. However, because the flexibility of ActionBar is not good, many software will choose to write and implement it by themselves. If we implement this by ourselves, since this header layout should be used on all interfaces, it is obviously impossible for us to write the code for this header layout in every interface, therefore, the <include> label is very suitable in this case. For demonstration, I will compile a very simple header layout. In the res/layout folder, create titlebar. xml as the header layout. The Code is as follows:

<?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" >    <Button        android:id="@+id/back"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentLeft="true"        android:layout_centerVertical="true"        android:text="Back" />    <TextView        android:id="@+id/title"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerInParent="true"        android:text="Title"        android:textSize="20sp" />    <Button        android:id="@+id/done"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentRight="true"        android:layout_centerVertical="true"        android:text="Done" /></RelativeLayout>
As you can see, titlebar. the layout in xml is very simple. The outer layer is a RelativeLayout with only two buttons and a TextView. The left Button is used to implement the return function, and the right Button is used to implement the Completion function, the TextView in the middle can be used to display the title of the current interface. Let's preview the titlebar, as shown in:


Okay, now we have finished writing titlebar as an independent layout, and the next work will be very simple. No matter whether you need to add titlebar to any interface, you only need to introduce titlebar in the layout file. xml. For example, there is an activity_main.xml file in our program. To introduce titlebar, you only need to write it like this:

<?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/titlebar" />    ......</LinearLayout>
It's very easy. You can do it with a line of include statements. <Include> You can specify a layout attribute in the tag. You can enter the layout name to be introduced in this layout attribute. In addition, if the titlebar interface is changed in the future, we only need to modify the titlebar. xml file, instead of modifying all interfaces one by one.

Wait! Now, if you run the program, you will find a major problem. Although titlebar is successfully introduced, all the original interfaces in activity_main.xml are missing! This problem occurs because the layout of the outermost layer of the titlebar is a RelativeLayout with both the width and height match_parent. It fills up the entire layout, so our original layout is invisible. Now that the cause of the problem is clear, I believe you will immediately think about how to modify it. Just change the layout_height attribute of RelativeLayout to wrap_content. Yes, this modification is of course correct, but this modification method will affect all the pages that reference titlebar. If you only want to make the activity_main.xml interface affected, you can overwrite the <include> attribute.

In the <include> label, we can override all layout attributes. That is, the layout attribute specified in include overwrites the layout attribute specified in titlebar. Therefore, we want to set the height of titlebar to wrap_content, so we can write it like this:

<?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        android:layout_width="match_parent"        android:layout_height="wrap_content"        layout="@layout/titlebar" />    ......</LinearLayout>
Run the program again, as shown in:


In addition to layout_height, We can overwrite any layout attribute in titlebar, such as layout_gravity and layout_margin. Other layout _height attributes cannot be overwritten in the <include> label. In addition, if you want to overwrite the layout attribute in the <include> tag, you must overwrite the layout_width and layout_height attributes, otherwise, the overwriting effect will not take effect.

<Merge>

<Merge> A label is used as a secondary extension of the <include> label. Its main function is to prevent redundant layout nesting when a layout file is referenced. As we all know, it takes time for Android to parse and display a layout. The more nested layout, the more time it takes to parse and the worse the performance, therefore, when writing layout files, the fewer layers of nesting, the better.

The advantages of the <include> label are described in the preceding section. However, there is also a bad problem, that is, redundant layout nesting may occur. Here we will give you an example. For example, you need to write a public layout for the confirm cancel button, so that you do not need to write a separate layout for any interface when you need to confirm or cancel the function, create OK _cancel_layout.xml with the following code:

<?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="wrap_content"    android:orientation="vertical" >    <Button        android:id="@+id/ok"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="20dp"        android:layout_marginRight="20dp"        android:text="OK" />    <Button        android:id="@+id/cancel"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="20dp"        android:layout_marginRight="20dp"        android:layout_marginTop="10dp"        android:text="Cancel" /></LinearLayout>
As you can see, this interface is also very simple. The outer layer is a vertical LinearLayout. LinearLayout contains two buttons, one for confirmation and the other for cancellation. Now we can preview this interface, as shown in:


Okay, then we need to edit some content on the profile. xml interface. Here we can introduce the OK _cancel_layout layout to the profile. xml interface, as shown below:

<?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" >        <EditText        android:id="@+id/edit"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginBottom="10dp"        android:layout_marginLeft="20dp"        android:layout_marginRight="20dp"        android:layout_marginTop="10dp"        android:hint="Edit something here" />        <include layout="@layout/ok_cancel_layout"/></LinearLayout>
In profile. xml, an EditText control is used to edit the content. The <include> label is used to introduce the OK _cancel_layout layout. Now, run the program again. The interface effect is shown in:


Looks pretty good, right? However, if you have no idea, there are already redundant layout nesting in the profile. xml interface! I feel that I haven't written a few lines of code yet. How can this cause redundant layout nesting? If you do not believe this, you can use the View Hierarchy tool to View the information, as shown in:


We can see that the outermost layer is first a FrameLayout, which is understandable. If you don't know why the outermost layer is FrameLayout, you can refer to it.Android LayoutInflater Principle Analysis, giving you a step-by-step insight into View (1)This article. FrameLayout contains a LinearLayout, which is the outermost layout defined in profile. xml. The next part is problematic. The LinearLayout on the outermost layer contains two elements: EditText and LinearLayout, then, the internal LinearLayout contains the buttons "OK" and "cancel.

As you can see, the internal LinearLayout is a redundant layout nesting. In fact, this layer is not required, so that the two buttons can be directly included in the external LinearLayout. This redundant layout Nesting is actually caused by the introduction of layout, because we have also defined a LinearLayout in OK _cancel_layout.xml. So how should we optimize this problem? Of course, the <merge> label is used to modify the code in OK _cancel_layout.xml, as shown below:

<?xml version="1.0" encoding="utf-8"?><merge xmlns:android="http://schemas.android.com/apk/res/android">    <Button        android:id="@+id/ok"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="20dp"        android:layout_marginRight="20dp"        android:text="OK" />    <Button        android:id="@+id/cancel"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="20dp"        android:layout_marginRight="20dp"        android:layout_marginTop="10dp"        android:text="Cancel" /></merge>
As you can see, here we delete the LinearLayout layout of the outermost layer of OK _cancel_layout and replace the <merge> label, which means that when there is a place to include this layout, the content contained in the <merge> label is directly filled to the include position, and no additional layout structure is added. Okay. The usage of <merge> is so simple. Run the program again and you will see that the interface has not changed. Then we can use the View Hierarchy tool to View the current View structure, as shown in:


OK. Now, EditText and the two buttons are directly included in LinearLayout, so there is no redundant layout nesting in our profile. xml.

Load the layout only when needed

Sometimes we may encounter such a scenario where there are many elements in a layout, but not all elements are displayed together, but only some commonly used elements are displayed under normal circumstances, the elements that are not commonly used are displayed only when the user performs a specific operation.

Here is an example that everyone is very familiar with. When adding a contact, we can actually edit a lot of fields, such as name, phone number, email, fax, address, nickname, etc, but basically, the most common thing is to fill in a name and a phone number. So it is not a good practice to display so many complicated fields together on the interface, because most people do not use these fields. The smartest way is to display the most common names and phone numbers on the interface, and then provide users with an option to add more fields, when users need to add other information, we can display other elements on the interface.

Speaking of implementing such a function, I believe that the first response of most people is to hide infrequently used elements using INVISIBLE or GONE, then, when users need to use these elements, they are displayed as VISIBLE. This method can certainly implement functions, but the performance is normal, because even if elements are hidden, they are still in the layout, each element also has its own attributes, such as width, height, and background. These hidden elements are parsed one by one during the parsing layout.

So how can we load these infrequently used elements only when necessary? Android provides ViewStub, a lightweight control. Although ViewStub is also a kind of View, it has no size, no painting function, and does not participate in layout. The resource consumption is very low, placing it in the layout is basically considered to have no impact on performance at all.

Next we will learn how to use ViewStub to load the layout only when needed. there is only one EditText in xml for editing information. For example, we have three other less commonly used edittexts, which can be defined in another layout file. Create a profile_extra.xml file. The Code is as follows:

<?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" >    <EditText        android:id="@+id/edit_extra1"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="20dp"        android:layout_marginRight="20dp"        android:hint="Extra field 1" />    <EditText        android:id="@+id/edit_extra2"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="20dp"        android:layout_marginRight="20dp"        android:layout_marginTop="10dp"        android:hint="Extra field 2" />    <EditText        android:id="@+id/edit_extra3"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="20dp"        android:layout_marginRight="20dp"        android:layout_marginTop="10dp"        android:hint="Extra field 3" /></LinearLayout>
As you can see, three edittexts are defined in the layout file profile_extra.xml, which is used to edit controls that do not commonly use information. Now we can preview the layout, as shown in:


Currently, profile_extra.xml is an independent layout. It has nothing to do with the layout File profile. xml. Next, modify the code in the profile. xml file as follows:

<?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" >    <EditText        android:id="@+id/edit"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginBottom="10dp"        android:layout_marginLeft="20dp"        android:layout_marginRight="20dp"        android:layout_marginTop="10dp"        android:hint="@string/edit_something_here" />    <Button        android:id="@+id/more"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="right"        android:layout_marginRight="20dp"        android:layout_marginBottom="10dp"        android:text="More" />        <ViewStub         android:id="@+id/view_stub"        android:layout="@layout/profile_extra"        android:layout_width="match_parent"        android:layout_height="wrap_content"        />    <include layout="@layout/ok_cancel_layout" /></LinearLayout>
We can see that here we have added a More Button, which is used to load those less commonly used elements, and then defines a ViewStub under the Button. In the ViewStub control, we first specify a unique identifier for it through the id attribute, and pass in the profile_extra layout through the layout attribute, and then specify a width and height for ViewStub. Note: Although ViewStub does not occupy any space, you must specify the layout_width and layout_height attributes for each layout. Otherwise, an error is reported during running.

Modify the code in ProfileActivity, add the click event of More Button to Activity, and perform the following logical processing in the click event:

private EditText editExtra1;private EditText editExtra2;private EditText editExtra3;public void onMoreClick() {ViewStub viewStub = (ViewStub) findViewById(R.id.view_stub);if (viewStub != null) {View inflatedView = viewStub.inflate();editExtra1 = (EditText) inflatedView.findViewById(R.id.edit_extra1);editExtra2 = (EditText) inflatedView.findViewById(R.id.edit_extra2);editExtra3 = (EditText) inflatedView.findViewById(R.id.edit_extra3);}}
After clicking More Button, we will first call the findViewById () method to retrieve the ViewStub instance. After obtaining the ViewStub instance, it is very easy to call the inflate () method or setVisibility (View. you can load the hidden layout, and the loaded layout is the profile_extra layout Just configured in XML.

After the inflate () method is called, The loaded layout is returned. Then, we can perform any operations on the layout, hide the display again, or obtain the instance of the child element. Note that I have made a non-null judgment on the ViewStub instance, because the id defined by ViewStub in XML is valid only at the beginning. Once the layout specified in ViewStub is loaded, this id fails, so the findViewById () value will also be empty.

Run the program again, as shown in the following figure:


As you can see, there is only one More button on the interface, and ViewStub does not occupy any space at all. Click the More button. The new interface is shown as follows:


No problem. The layout defined in profile_extra.xml has been loaded and displayed between the More button and the OK button, which is exactly the position defined by the ViewStub control, it indicates that ViewStub has been successfully used.

We also need to remind you that the <merge> label cannot be used for the layout loaded by ViewStub. Therefore, this may lead to redundant nested structures in the loaded layout, the specific choice depends on the actual situation. for situations where the hidden layout file structure is quite complex, using ViewStub is still a pretty good choice, even if a useless layout structure is added, the advantage is greater than the disadvantage.

After four articles, we have learned a lot of skills to improve the performance of Android applications. Most of these skills are from Android Doc, I also selected some practical parts from them, and then added my own understanding to present them to everyone. If you want to continue learning

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.