[Andorid Application Development]-(3) Performance Optimization Design

Source: Internet
Author: User

This article describes performance design. I estimate that many children's shoes have not seen the original article. Here we recommend that you see the article from the Android official website and the downloaded Android Docs Dev Guide. If you have not read this article, I strongly recommend that you read it carefully.


An Android app runs on a mobile device with limited computing power, storage space, and limited battery life. In view of this, the application should be efficient. Even if your program looks "fast enough", the battery life may be one reason you want to optimize your application. For users, the battery life is important. Android battery depletion means that users will know that your applications have exhausted the battery.

Please note that although this article mainly describes micro-optimization, these optimizations will hardly damage your applications. Your primary task is to select an appropriate algorithm and data structure, but these are not covered in this article.

Directory [hide]
1 Overview
2. perform optimization wisely
3. Avoid creating unnecessary objects
4. Myth of Performance Optimization
5. Better static method than virtual Method
6. Do not use getter and setter in the class.
7. Use Static Final to modify Constants
8. Use the for-each syntax
9. Declare the variables used with the internal class within the package range.
10 avoid using floating point numbers
11 understand and use the class libraries provided by Android
12 use JNI with caution to call local methods
13 conclusion
 

Introduction
The following are two basic principles for writing efficient code:

Do not do unnecessary things
Do not allocate unnecessary memory
Smart Optimization
This document is about the micro-optimization of the Android platform. It is assumed that you have analyzed the program and learned that the code needs to be optimized, and you already have a way to measure the results (good or bad) of any changes you make ). You only have time to invest in projects. What's important is that you know that you use them wisely.

(See # conclusion to learn more about analyzing applications and writing Efficient Test Standards)

At the same time, this document assumes that you have chosen the correct data structure and algorithm, and consider the performance impact of changing your program. The impact of correct selection of data structures and algorithms is significantly different from all the suggestions provided in this document, predicting the performance impact of your changes will help you switch to a better implementation solution (this is more important to the class library code than the application code ).

(If you need suggestions in this regard, you can refer to Josh Bloch to write the objective Java, article 1)

When you perform micro-optimization on your Android Application, you will encounter a tricky problem: Make sure that your application runs on multiple hardware platforms. Virtual machines of different versions run at different speeds on different processors. You can say that "device X is faster/slower than device y f times", but this conclusion cannot be extended from one device to another. In particular, your testing results on the simulator do not tell you how the performance is on any other device. Likewise, devices that use JIT are quite different from those that do not use JIT: the code that runs the "best" performance on devices that use JIT may not be suitable for devices that do not use JIT.

If you want to know how your application runs on a specified device, you need to perform a test on the device.

Avoid creating unnecessary objects
Creating objects is not free of charge. Although GC creates a temporary object pool for each thread, it can reduce the cost of object creation, but the cost of memory allocation is always higher than that of memory allocation.

If you allocate the object memory in the user interface loop, it will lead to periodic garbage collection, and the user will feel that the interface is as choppy. Although the concurrent collector introduced by Android2.3 helps garbage collection, unnecessary work should be avoided.

Therefore, avoid creating unnecessary object instances. The following example will help you understand this principle:

If you have a function that returns a String object, and you know exactly that the String will be appended to a StringBuffer, change the parameter and implementation method of this function, directly append the result to StringBuffer, instead of creating a short-lived temporary object.
When you extract a string from user input data, try to use the substring function to obtain a substring of the original data, instead of creating a copy for the substring. In this way, you have a new String object, which shares a char array with the original data. (If you only use a small part of the original input, you will keep it in the memory)
A more extreme example is to divide a multi-dimensional array into multiple one-dimensional arrays.

The int array is better than the Integer array, which also summarizes the basic fact that two parallel int arrays provide much better performance than the array of (int, int) objects. Similarly, this is intended for a combination of all basic types.
If you want to use a container to store (Foo, Bar) tuples, try to use two separate Foo [] arrays and Bar [] arrays, which must be equal to (Foo, Bar) array efficiency is higher. (There is also an exception, that is, when you create an API to allow others to call it. At this time, you should pay attention to the design of API excuses and sacrifice a little speed. Of course, you still need to improve the code efficiency as much as possible within the API)
In general, it is to avoid creating short-lived temporary objects. Reduce the creation of objects to reduce the garbage collection, and thus reduce the impact on user experience.

Myth of Performance Optimization
Here we will clarify the misleading statements caused by previous versions of this document.

In devices that do not use JIT, calling an interface takes more time to reference than calling an object class (for example, calling a map of the HashMap type is lower than calling a Map of the map type. Even in both cases, the map is a HashMap instance ). This is not twice as slow as previously mentioned. It is actually 6% slower. Besides, JIT effectively distinguishes the two.

On devices that do not use JIT, local variables that access the cache are about 20% faster than those that call the member variable repeatedly. In devices using JIT, the cost of accessing local variables is the same as that of accessing member variables, so this is not a good optimization measure, unless you think this will make your code easier to read (this recommendation applies to final, static, and final static modified member variables ).

Static method is better than virtual Method
If you do not need to access the member variables of an object, declare the method as static. Static method calls are faster than 15-20%. This is a good technique, because you can call this function through the method signature without changing the object state.

Do not use getter and setter in the class.
In many local languages such as C ++, using getter (for example, I = getCount () instead of directly accessing the member variable (I = mCount) is a common usage. This is a good habit in C ++, because the compiler can be accessed inline. If you need to constrain or debug variables, you can add code at any time.

On Android, this is not a good idea. The overhead of the virtual method is much greater than that of directly accessing the member variable. When designing public interfaces, getters and setters can be defined according to the common object-oriented approach. However, you should directly access variables within a class.

On devices without JIT, directly accessing member variables is about three times faster than calling a simple getter method. On devices with JIT, directly accessing member variables is about seven times faster than calling a simple getter method. Currently, this is a fact in Froyo (android2.2). We will improve the efficiency of JIT inline getter methods in later versions.

Use Static Final to modify Constants
Let's take a look at the Declaration of the two paragraphs before the class:

Static int intVal = 42;
Static String strVal = "Hello, world! ";
The compiler generates an initialization class method called <clinit>, which is executed when the class is used for the first time. This method will assign 42 to intVal, and then assign a reference pointing to a common table in the class to strVal. If you want to use these values later, you can find them in the member variable table.

Here we use the "final" keyword to make some improvements:

Static final int intVal = 42;
Static final String strVal = "Hello, world! ";
Currently, the <clinit> method is no longer required for classes, because constants are directly saved to class files during member variable initialization. The intVal code is directly replaced with 42, and the strVal code points to a String constant with a relatively low cost, instead of using member variables (note that this optimization only applies to basic types and string constants, rather than reference types. However, this is still a very popular practice. You should declare constants as static final as much as possible ).

Use the for-each syntax
The enhanced for loop (sometimes called for-each loop) can be used in the set types and arrays that implement the Iterable interface. For a set, an iterator means that the hasNext () and next () methods can be called. In ArrayList, the hand-written counting cycle is about three times faster than the for-each loop, but for other collection classes, foreach is equivalent to using iterator.

The following shows three optional methods for traversing an array:

Static class Foo {
Int mSplat;
}
Foo [] mArray =...
 
Public void zero (){
Int sum = 0;
For (int I = 0; I <mArray. length; ++ I ){
Sum + = mArray [I]. mSplat;
}
}
 
Public void one (){
Int sum = 0;
Foo [] localArray = mArray;
Int len = localArray. length;
 
For (int I = 0; I <len; ++ I ){
Sum + = localArray [I]. mSplat;
}
}
 
Public void two (){
Int sum = 0;
For (Foo a: mArray ){
Sum + = a. mSplat;
}
}
Zero () is the slowest, because every iteration of the loop gets the length of the array once, which is not optimized by JIT.

One () is faster than zero (). It saves all variables with local variables to avoid searching. However, simply storing the length of an array increases the efficiency.

Two () uses the foreach syntax introduced in java1.5. For devices without JIT, this method is the fastest, differentiated by the one () that uses JIT ().

To sum up, the enhanced for (foreach) can be used by default. When ArrayList traversal affects key performance, a handwritten counting loop is considered. (For details, refer to objective Java 46th)

Declare the variables used with the internal class within the package range.
See the following class definitions:

Public class Foo {
Private class Inner {
Void stuff (){
Foo. this. doStuff (Foo. this. mValue );
}
}
 
Private int mValue;
 
Public void run (){
Inner in = new Inner ();
MValue = 27;
In. stuff ();
}
 
Private void doStuff (int value ){
System. out. println ("Value is" + value );
}
}
The key here is that we define a private internal class (Foo $ Inner) that needs to access the private member variables and functions of the external class. This is syntactic and will print the expected result "Value is 27 ″.

The problem is that Foo AND Foo $ Inner are two different classes. virtual machines believe that it is illegal to directly access the Private Members of the Foo class in the Foo $ Inner class, even if the java language allows internal classes to access private variables of external classes. To overcome this obstacle, the compiler generates a set of intermediate methods:

/* Package */static int Foo. access $100 (Foo foo ){
Return foo. mValue;
}
/* Package */static void Foo. access $200 (Foo foo, int value ){
Foo. doStuff (value );
}
When an internal class accesses mValue or calls the doStuff method of an external class, these static methods are called. That is to say, the code above illustrates a problem where you access these member variables and functions through interface methods rather than directly calling them. As we have mentioned earlier, the use of interface methods (getter and setter) is slower than the direct access speed. Therefore, this example is a "implicit" performance obstacle under a specific syntax.

If your code is similar, you can avoid overhead by changing the variables and function declarations accessed by internal classes from private range to package range. Unfortunately, these domains and methods can be directly accessed by other classes in the same package. Therefore, you should exercise caution when designing public APIs.

Avoid floating point number
Generally speaking, floating point numbers on Android devices are two times slower than integers. This is true in the absence of FPU and JIT G1 and in the use of FPU and JIT Nexus. (Of course, the computing speed difference between the two is about 10 times)

In terms of speed, there is no significant difference between double and float in the face of modern hardware. In terms of space, double occupies 2 times the space of float. If your space is the same as that of a desktop, you can use double instead of float.

Likewise, even an integer, some chips have hardware support for multiplication but lack Division support. In this case, the division and modulo operations of integers are completed by software-you can imagine what you do when designing a hash table or doing a large number of mathematical operations (you will know how low the efficiency is. ).

Understand and use the class libraries provided by Android
In addition to the special reasons, we recommend that you use the class libraries provided by android instead of your own. Remember that the Android system will optimize and expand the existing java class libraries, this is obviously more efficient than the original JIT class library. A typical example is that Dalvik optimized the String. indexOf method using inline, and also the System. arraycopy method, which is about 9 times faster than the Nexus One using JIT. (For details about this article, refer to Article 47th of objective Java)

Use JNI with caution to call local methods
Local Code is not necessarily more efficient than java code. First, the transition from java to local code requires overhead, and JIT cannot be optimized. If you allocate local resources (local memory, files, or any other resources) in your local code, it is more difficult to collect these resources in a timely manner. At the same time, you need to compile different code for different architecture platforms (instead of relying on JIT to provide you with a set ). You even need to compile multiple versions of code on the same platform. (The Local Code Compiled by the G1 ARM processor and the Local Code Compiled by the ARM processor on the Nexus One are not universal)

When you already have a local code library and want to use the code for android, you can use JNI to call the local code. In fact, the use of local methods to improve performance since java1.3 is not worth advocating.

If you need local code, refer to JNI Tips. (For more information, see objective Java 54th)

Conclusion
The last thing: Continuous testing. Optimization with problems should be carried out to ensure that you can accurately measure the performance before optimization, otherwise you will not be able to measure the performance optimization you are trying to make.

Each item in this document has corresponding standards, which can be found in the code.google.com "dalvik" project.

These standards are built on Caliper's java framework. Even so, the "micro-standard" is hard to measure. This project Caliper can help you, and we strongly recommend that you use this framework here.

You may also find that you can use Traceview to analyze the program, but you must realize that JIT is disabled currently, which leads to incorrect calculation of JIT call time. Make sure that the optimization caused by using Traceview data is indeed better than not using Traceview.

 


The Android performance optimization principles and methods mentioned in this article may be a bit confusing after reading. We usually develop to process some simple data or implement a simple function, without involving algorithms or internal classes. So how to optimize our program? Below I will perform Code micro-optimization for several common programming methods. When developing Android applications, we should also remember that the mobile phone or MID memory is quite limited, developing applications should try to make them execute code efficiently, rather than making a waste of effort like a J2EE program. Many kids Shoes bring their previous J2EE development experience to Android Application Development. In fact, these are just details. Pay more attention to them.

1. For how to obtain the length of arrays and lists, see the following code.
[Java]
<SPAN style = "FONT-SIZE: 16px"> List <String> list = new ArrayList <String> ();
For (int I = 0; I <100; I ++ ){
List. add ("abcdefg ");
}
Long startTime1 = System. currentTimeMillis ();
For (int I = 0; I <list. size (); I ++ ){
System. out. println (list. get (I ));
}
Long endTime1 = System. currentTimeMillis ();
Log. e (TAG, "time:" + (endTime1-startTime1 ));
//////////////////////////////////////// /////
Long startTime2 = System. currentTimeMillis ();
Int size = list. size ();
For (int I = 0; I <size; I ++ ){
System. out. println (list. get (I ));
}
Long endTime2 = System. currentTimeMillis ();
Log. e (TAG, "time:" + (endTime2-startTime2); </SPAN>

List <String> list = new ArrayList <String> ();
For (int I = 0; I <100; I ++ ){
List. add ("abcdefg ");
}
Long startTime1 = System. currentTimeMillis ();
For (int I = 0; I <list. size (); I ++ ){
System. out. println (list. get (I ));
}
Long endTime1 = System. currentTimeMillis ();
Log. e (TAG, "time:" + (endTime1-startTime1 ));
//////////////////////////////////////// /////
Long startTime2 = System. currentTimeMillis ();
Int size = list. size ();
For (int I = 0; I <size; I ++ ){
System. out. println (list. get (I ));
}
Long endTime2 = System. currentTimeMillis ();
Log. e (TAG, "time:" + (endTime2-startTime2 ));

Through the simple method above, combined with printed information, we can see that the recycling efficiency of getting the list first is about twice as high! So what should I do in your program?

2. Android static variables
Android static variables have a feature, that is, static variables exist when the application is closed. See the following code snippet.

[Java]
<SPAN style = "FONT-SIZE: 16px"> private static int I = 10;
@ Override
Public void onCreate (Bundle savedInstanceState ){
Super. onCreate (savedInstanceState );
SetContentView (R. layout. main );
Log. e (TAG, "I =" + I );
I = 15;
}
@ Override
Protected void onDestroy (){
Log. e (TAG, "onDestroy ======== ");
// Android. OS. Process. killProcess (android. OS. Process. myPid ());
Super. onDestroy ();
} </SPAN>

Private static int I = 10;
@ Override
Public void onCreate (Bundle savedInstanceState ){
Super. onCreate (savedInstanceState );
SetContentView (R. layout. main );
Log. e (TAG, "I =" + I );
I = 15;
}
@ Override
Protected void onDestroy (){
Log. e (TAG, "onDestroy ======== ");
// Android. OS. Process. killProcess (android. OS. Process. myPid ());
Super. onDestroy ();
} Run the application twice. The following result is displayed:

 

How are you doing? Interesting! To avoid this situation, you can. add this code to the onDestroy method: android. OS. process. killProcess (android. OS. process. myPid (); kill the process in which the current application is located. If you do not kill it, use static with caution, just as the above Code does not destroy and leads to incorrect initial values of I. Of course, there is another way to achieve the static effect. That is to inherit the Application to achieve the purpose of using multiple activities and services. We all know that all activities, services, and Broadcast in Android apps indirectly inherit Context. In the AndroidManifest. xml configuration file, all activities and services are included in the tag Application. All activities and services can call non-private methods and variables in the Application. Therefore, you can inherit the Application to customize an Application subclass. Of course, as long as the control is complete, there is no problem.

3. For more information about Android layout optimization, see the next blog. It is very important and has many knowledge points ~

Author: tangcheng_ OK
 

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.