Android-Basic Knowledge: Compile efficient android code

Source: Internet
Author: User

From: http://www.cnblogs.com/mudoot/archive/2011/11/16/Writing_Efficient_Android_Code.html for postscript.

There are two basic principles for a resource-consuming system:

    Do not do unnecessary things

    Do not allocate unnecessary memory

1. Avoid object Creation    

Unless necessary, try to avoid the instance of the best effort 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 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.

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)

2. Use the local method

When processing strings, do not use special implementation methods such as String. indexOf () and String. lastIndexOf. These methods are implemented using C/C ++, which is 10 to 100 times faster than Java loops.

However, it is not necessary to use the local method completely. The cost of calling the local method is higher than that of calling the interpretation method. So if you can avoid this, you should not use local methods to perform some non-complex operations.

3. Select virtual classes instead of interfaces.

Suppose you have a HashMap object. You can declare it as a HashMap or Map:

    Map myMap1 = new HashMap();    HashMap myMap2 = new HashMap();

Which one is better?

In the traditional view, Map is better, because you can change its specific implementation class as long as the class inherits from the Map interface. The traditional view is correct for traditional programs, but it is not suitable for embedded systems. Calling an interface takes twice as long as calling an object class.

If HashMap is perfect for your program, using Map has no value. If you are not sure about some items, avoid using Map first, and leave the rest to the refactoring function provided by IDE. (Of course, a public API is an exception: A good API often sacrifices some performance)

 

4. Better static method than virtual Method

If you do not need to access the member variables of an object, declare the method as static. The virtual method runs faster because it can be called directly without a virtual function table.

In addition, you can declare that the function call does not change the object state.

 

5. getter and setter are not required.

In many local languages such as C ++, getter (for example, I = getCount () is used to avoid direct access to the member variable (I = mCount ). 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. In the general interface definition, getters and setters can be defined according to the OO method, but in the general class, you should directly access the variable.

 

6. cache member variables locally

Accessing member variables is much slower than accessing local variables. The following code:

    for (int i = 0; i < this.mCount; i++)      dumpItem(this.mItems[i]);

You should write it:

    int count = this.mCount;    Item[] items = this.mItems;    for (int i = 0; i < count; i++)      dumpItems(items[i]);

(This is used to indicate that these are member variables)

Another similar principle is:Never call any method in the second condition of. As shown in the following method, the getCount () method is called every time a loop is executed, which is much more overhead than saving the result in an int.

  for (int i = 0; i < this.getCount();i++)    dumpItems(this.getItem(i)); 

Similarly, if you want to access a variable multiple times, you 'd better create a local variable for it first, for example:

Protected void drawHorizontalScrollBar (Canvas canvas, int width, int height ){

If (isHorizontalScrollBarEnabled ()){

Int size =MScrollBar. GetSize (false );

If (size <= 0 ){

Size = mScrollBarSize;

}

MScrollBar. SetBounds (0, height-size, width, height );

MScrollBar. SetParams (

ComputeHorizontalScrollRange (),

Computehorizontalscroloffset (),

ComputeHorizontalScrollExtent (), false );

MScrollBar. Draw (canvas );

}

}

Here, the member variable mScrollBar is accessed four times. If it is cached locally, the four member variable accesses will become four more efficient stack variable accesses.

By the way, the performance of method parameters is the same as that of local variables.


7. Use 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. The method will assign 42 to intVal, and then assign a reference pointing to a common table in the class to strVal. When these values are used in the future, they will be found in the member variable table.

We can make some improvements by using the keyword "final:

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 code that uses intVal is directly replaced with 42, and strVal points to a String constant instead of a member variable.

Declaring a method or class as "final" will not improve the performance, but will help the compiler optimize the code. For example, if the compiler knows that a "getter" method will not be overloaded, the compiler will call it inline.

You can also declare the local variable as "final" without performance improvement. Using "final" can only make the local variables look clearer (but sometimes this is required, for example, when using anonymous internal classes ).

 

8. Use foreach with caution

Foreach can be used in the collection type that implements the Iterable interface. Foreach assigns an iterator to these objects and then calls the hasNext () and next () methods. You 'd better use foreach to process the ArrayList object, but for other set objects, foreach is equivalent to using iterator.

The following describes an acceptable foreach usage:

Public class Foo {

Int mSplat;

Static Foo mArray [] = new Foo [27];

Public static void zero (){

Int sum = 0;

For (int I = 0; I <mArray. length; I ++ ){

Sum + = mArray [I]. mSplat;

}

}

Public static void one (){

Int sum = 0;

Foo [] localArray = mArray;

Int len = localArray. length;

For (int I = 0; I <len; I ++ ){

Sum + = localArray [I]. mSplat;

}

}

Public static void two (){

Int sum = 0;

For (Foo a: mArray ){

Sum + = a. mSplat;

}

}

}

InZero(), Each loop will access two static member variables to get the length of an array.

InOne(), Store all member variables to local variables.

InTwo(), The foreach syntax introduced in Java is used. The compiler saves the array reference and length to the local variable, which is very good for accessing array elements. However, the compiler will also generate an additional storage operation on local variables (access to variable a) in each loop, which will be 4 bytes more than one, the speed is a little slower.

To sum up, when foreach accesses the array, it has good performance, but should be careful when using other set objects because it will produce additional objects.

 

9. Avoid Enumeration

It is very convenient to enumerate variables, but unfortunately it will sacrifice the execution speed and greatly increase the file size. For example:

Public class Foo {

Public enum Shrubbery {GROUND, crawler, HANGING}

}

A 900-byte. class file (Foo $ Shubbery. class) is generated ). When it is called for the first time, this class will call the initialization method to prepare each enumerated variable. Each enumeration item is declared as a static variable and assigned a value. Put these static variables in a static array variable named "$ VALUES. So much code is just to use three integers.

In this case, Shrubbery shrub = Shrubbery. GROUND; declares a reference to the static variable. If the static variable is a final int, the compiler will inline the constant directly.

On the one hand, using enumeration variables can make your API better and provide compile-time checks. Therefore, in general, you should select an enumeration variable for the public API. However, when performance is limited, you should avoid this practice.

In some cases, it is better to use the ordinal () method to obtain the integer of the enumerated variable. For example, we will:

For (int n = 0; n <list. size (); n ++ ){

If (list. items [n]. e = MyEnum. VAL_X)

// Do stuff 1

Else if (list. items [n]. e = MyEnum. VAL_Y)

// Do stuff 2

}

Replace:

Int valX = MyEnum. VAL_X.ordinal ();

Int valY = MyEnum. VAL_Y.ordinal ();

Int count = list. size ();

MyItem items = list. items ();

For (int n = 0; n <count; n ++)

{

Int valItem = items [n]. e. ordinal ();

If (valItem = valX)

// Do stuff 1

Else if (valItem = valY)

// Do stuff 2

}

It will improve the performance, but this is not the final solution.

10. Declare the internal class within the package Scope

Consider the following class definitions:

Public class Foo {

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 );

}

Private class Inner {

Void stuff (){

Foo. this. doStuff (Foo. this. mValue );

}

}

}

The key here is that we define an internal class (Foo $ Inner) that needs to access the private domain variables and functions of the external class. This is legal and will print the expected result "Value is 27 ".

Technically (behind the scenes) Foo $ Inner is a completely independent class, and it is illegal to directly access the private members of Foo. To bridge this gap, the compiler must generate a set of 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 );

}

Each time an internal class accesses the "mValue" and "doStuff" methods, 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.

We can avoid this problem by changing the variable and function declaration for internal class access from private range to package range. This can make the code run faster and avoid generating additional static methods. (Unfortunately, these domains and methods can be directly accessed by other classes in the same package, which is contrary to the classic OO principle. Therefore, you should use this optimization principle with caution when designing public APIs)

11. Avoid Enumeration

It is very convenient to enumerate variables, but unfortunately it will sacrifice the execution speed and greatly increase the file size. For example:

Public class Foo {

Public enum Shrubbery {GROUND, crawler, HANGING}

}

A 900-byte. class file (Foo $ Shubbery. class) is generated ). When it is called for the first time, this class will call the initialization method to prepare each enumerated variable. Each enumeration item is declared as a static variable and assigned a value. Put these static variables in a static array variable named "$ VALUES. So much code is just to use three integers.

In this case, Shrubbery shrub = Shrubbery. GROUND; declares a reference to the static variable. If the static variable is a final int, the compiler will inline the constant directly.

On the one hand, using enumeration variables can make your API better and provide compile-time checks. Therefore, in general, you should select an enumeration variable for the public API. However, when performance is limited, you should avoid this practice.

In some cases, it is better to use the ordinal () method to obtain the integer of the enumerated variable. For example, we will:

For (int n = 0; n <list. size (); n ++ ){

If (list. items [n]. e = MyEnum. VAL_X)

// Do stuff 1

Else if (list. items [n]. e = MyEnum. VAL_Y)

// Do stuff 2

}

Replace:

Int valX = MyEnum. VAL_X.ordinal ();

Int valY = MyEnum. VAL_Y.ordinal ();

Int count = list. size ();

MyItem items = list. items ();

For (int n = 0; n <count; n ++)

{

Int valItem = items [n]. e. ordinal ();

If (valItem = valX)

// Do stuff 1

Else if (valItem = valY)

// Do stuff 2

}

It will improve the performance, but this is not the final solution.

12. Declare the internal class within the package Scope

Consider the following class definitions:

Public class Foo {

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 );

}

Private class Inner {

Void stuff (){

Foo. this. doStuff (Foo. this. mValue );

}

}

}

The key here is that we define an internal class (Foo $ Inner) that needs to access the private domain variables and functions of the external class. This is legal and will print the expected result "Value is 27 ".

Technically (behind the scenes) Foo $ Inner is a completely independent class, and it is illegal to directly access the private members of Foo. To bridge this gap, the compiler must generate a set of 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 );

}

Each time an internal class accesses the "mValue" and "doStuff" methods, 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.

We can avoid this problem by changing the variable and function declaration for internal class access from private range to package range. This can make the code run faster and avoid generating additional static methods. (Unfortunately, these domains and methods can be directly accessed by other classes in the same package, which is contrary to the classic OO principle. Therefore, you should use this optimization principle with caution when designing public APIs)

13. Avoid using floating point numbers.

Before the emergence of the Pentium CPU, the game designers did the most integer operations. With the arrival of the Pentium, the floating point computing processor has become a built-in feature of the CPU. The use of floating point and integer can make your game run more smoothly. Generally on a desktop computer, you can use floating point operations at will.

Unfortunately, embedded processors generally do not have hardware that supports floating-point operations. All operations on "float" and "double" are implemented through software. Some basic floating point operations can be completed in milliseconds.

It is 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 also completed by software. Therefore, be cautious when using hash tables or performing a large number of mathematical operations.

 

Conclusion

The best way to write correct and efficient code for embedded systems is to understand what your code is to do. If you really want to allocate an iterator or use the enhanced loop syntax on Lists anyway, it must be a well-thought-out option, rather than a side effect. Everything should be done before it is done. Be sure to know what you are doing. Write the code according to your own style, but you must carefully consider what the code is doing and find a way to increase the speed.

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.