Android App performance Optimization tips

Source: Internet
Author: User
Tags benchmark

Mainly introduces some small details of the optimization techniques, although these tips can not be significantly improved application performance, but the appropriate use of these tips and the cumulative effect of the time, for the overall performance of the app is not a small effect. In general, choosing the right algorithm and data structure will be your primary consideration and will not be covered in this article. You should use the tips in this article as a habit of writing code, which can improve the efficiency of your code.

In general, efficient code needs to meet the following two principles:

Don't do redundant work.

Try to avoid excessive memory allocation operations

To ensure your apps performs well across a wide variety of devices, ensure your code was efficient at all levels and Agressi Vely optimize your performance. Goal: To ensure that your app works well on every device, make sure your code is optimized as much as possible on a variety of devices.

The following methods can be used to optimize the code:

Method One: Avoid creating unnecessary objects

Object creation is never free. Creating an object is never free. The generational GC (with per-thread allocation pools) can make the allocation of temporary objects cheaper, but it is always more expensive to perform allocated memory than to perform allocation operations. As you assign more objects to the app, you may need to force the GC, and the GC operation will be a bit of a lag for the user experience. Although the concurrent GC has been introduced from Android 2.3, it can help you significantly increase the efficiency of the GC and reduce the lag, but the unnecessary memory allocation operation should be avoided as much as possible.

So try to avoid creating unnecessary objects, here are some examples to illustrate this problem:

If you had a method returning a string, and you know the its result would always be appended to a stringbuffer anyway, ch Ange your signature and implementation so, the function does the append directly, instead of creating a short-lived TE Mporary object. If you need to return a string object and you know that it will eventually need to be connected to a stringbuffer, modify your function implementation to avoid direct connection operation, you should create a temporary object to do the concatenation of the string.

When extracting strings from a set of input data, try to return a substring of the original data, instead of creating a Co Py. You'll create a new String object, but it'll share the char[] with the data. (The trade-off being if you ' re is only using a small part of the original input and you'll be keeping it all around in memo Ry anyway if you go this route.) When extracting a string from an already existing dataset, try returning the substring object of the original data instead of creating a duplicate object. Using substring, you will get a new string object, but this string object shares the internal char[] space with the original string.

A slightly more aggressive approach is to decompose all multidimensional data into one-dimensional arrays:

An array of ints are a much better than an array of integers objects, but this also generalizes to the fact that both Paralle L Arrays of INTs is also a lot more efficient than an array of (Int,int) objects. The same goes for any combination of primitive types. A set of int data is much better than a set of integer objects. It can be learned that two sets of one-dimensional arrays are more efficient than a two-dimensional array. Similarly, this can be generalized to other primitive data types.

If you need to implement a container this stores tuples of (Foo,bar) objects, try to remember that both parallel foo[] and Bar[] Arrays is generally much better than a single array of custom (Foo,bar) objects. (The exception to this, of course, was when you ' re designing an API for other code to access. In those cases, it's usually better to make a small compromise to the speed of order to achieve a good API design. Your own internal code, you should try and be as efficient as possible.) If you need to implement an array to hold (Foo,bar) objects, remember to use foo[] and bar[] much better than (Foo,bar). (The exception is that some compromises can be made appropriately for the design of some good APIs.) But inside your own code, you should use a lot more easily after decomposition.

In general, you need to avoid creating more temporary objects. Fewer objects mean fewer GC actions, and the GC has a more direct impact on the user experience.

Method Two: Use static instead of virtual

If you do not need to access the value of an object, make sure that the method is static type, so that the method call will be 15%-20% faster. This is a good habit, because you can tell from the method declaration that the call cannot change the state of the object.

If you don't need to access a object ' s fields, make your method static. Invocations'll is about 15%-20% faster. It's also good practice, because can tell from the method signature that calling the method can ' t alter the object's S Tate.

Method Three: Constants declared as static final

Consider the following statement:

static int intval = 42;
static String Strval = "Hello, world!";

The compiler uses a function that initializes the class (named: Clinit) and executes when the class is first used. This function stores 42 in Intval and extracts the Strval reference from the constant table of the class file. When using Intval or Strval later, they will be queried directly.

You can use the final declaration to optimize:

static final int intval = 42;
Static final String Strval = "Hello, world!";

The above method is no longer required because the constants of the final declaration enter the domain initialization part of the static Dex file. The code that calls Intval uses 42 directly, and the code that calls Strval uses a relatively inexpensive "string constant" directive, rather than a table check.

It is important to note that this optimization method is valid only for the original type and string type, not for any reference type. However, it is a good practice to use static final when necessary.

Method Four: Avoid the internal getters/setters

Native language, such as C + +, typically use getters (i = GetCount ()) instead of directly accessing the variable (i = mCount). This is a good habit of writing C + + and is often used by other object-oriented languages, such as C # and Java, because compilers usually do inline access, and you need to restrict or debug variables, you can add code to getter/setter at any time.

However, on Android, this is not a good notation. The call to a virtual function consumes more than a direct access variable. In object-oriented programming, it is reasonable to expose getter and setting to the public interface, but within the class you should only use domain direct access.

When there is no JIT (Just in time Compiler), direct access to the variable is 3 times times faster than the call getter. When there is a JIT, direct access to the variable is 7 times times faster than the getter access.

Please note that if you use Proguard, you can get the same effect because Proguard can be accessors for you.

Method Five: Use enhanced for loop

The enhanced for loop (also known as the For-each Loop) can be used on collections and arrays that implement the Iterable interface. When using collection, iterator is allocated for For-each calls to the Hasnext () and Next () methods. With ArrayList, the handwritten count for loop will be 3 times times faster (with or without JIT), but for other collection, the enhanced For-each loop will be as efficient as the iterator notation.

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 () {    int sum = 0;    for (Foo a:marray) {        sum + = A.msplat;    }}

The efficiency analysis is as follows:

Zero () is the slowest because the JIT has no way to optimize it.
One () is a little faster.
Both () are the quickest when they are not JIT, but if they are JIT, they are almost as fast as method one (). It uses the enhanced loop method For-each.

So try to use the For-each method, but for ArrayList, use method one ().

Why is there an inner class in the ArrayList class: Arraylistiterator. The inner class is declared as follows:

Private class Arraylistiterator implements Iterator<e> {/** number of elements remaining in this        iteration */
   private int remaining = size;        /** Index of element that remove () would remove, or-1 if no such ELT *        /private int removalindex =-1;        /** the expected Modcount value */        private int expectedmodcount = Modcount;        public Boolean Hasnext () {            return remaining! = 0;        }   ......

Method Six: Use package-level access instead of private internal class access

Consider the following code:

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 =;        In.stuff ();    }    private void Dostuff (int value) {        System.out.println ("value is" + value);}    }

What's important here is that we define a private inner class (Foo$inner) that accesses private methods and private member objects directly in the outer class. This is legal, and the code prints "Value is 27" as expected. The problem is that VMS because Foo and Foo$inner are different classes, it is considered illegal to access the private members of the Foo class directly in Foo$inner. Even though the Java language allows internal classes to access private members of external classes.

/*package*/static int foo.access$100 (foo foo) {    return foo.mvalue;} /*package*/static void foo.access$200 (foo foo, int value) {    Foo.dostuff (value);}

It calls these static methods whenever an internal class needs to access an Mvalue member in an external class or needs to call the Dostuff () function. This means that the above code can be attributed to the use of the accessor function to access the member variable. As we said earlier, passing accessor would be slower than accessing the domain directly. So, this is an example of a performance degradation caused by a particular language usage.

If you are using code like this in the performance Hot Zone (hotspot: High frequency, repeating code snippet), you can declare the domains and methods that the inner class needs to access as package-level access, rather than private access. Unfortunately, this means that other classes in the same package can also access these domains directly, so you cannot do so in the exposed API.

Method Seven: Avoid using float type

The data access speed for the float type in Android is half the type of int, as much as possible with the int type. In terms of speed, the speed of float and double is the same on modern hardware. In terms of space, double is twice times the size of float. In situations where space is not an issue, you should use double. Similarly, for integer types, some processors implement multiplication of hardware several times, but no division. At this point, the division and remainder of the integer is implemented within the software, which you should take into account when you use a hash table or a large number of computation operations.

Method Eight: Use library functions

In addition to the usual reasons for you to use your own library functions, remember that system functions can sometimes replace third-party libraries, and there are assembly-level optimizations that are often more efficient than code with JIT-compiled java. A typical example is the String.IndexOf () in the Android API, which is replaced by Dalvik for inline performance reasons. The same system.arraycopy () function is also replaced, so the performance is 9 times times faster than the handwritten for loop and using the JIT in the Nexus One Test.

Method Nine: Use the native method cautiously

Combining the Android NDK with native code development is not always more efficient than direct Java development. Java-to-native code is a cost, and JIT cannot be optimized in this case. If you allocate resources in the native code (such as memory on the native heap, file descriptors, and so on), this can cause great difficulty in collecting these resources. You also need to recompile the code for various architectures (rather than relying on JIT). You even need to compile multiple versions of a device that already has the same architecture: the version compiled for the G1 arm architecture does not fully utilize the benefits of the ARM architecture on Nexus One, and vice versa.

The Native code is an advantage when you already have native code that you want to port to the Android platform, rather than to optimize the existing Android Java code usage.

If you want to use JNI, learn JNI Tips.

Method Ten: The error of performance optimization

On devices that do not have a JIT, it is really more efficient to use an exact data type than the abstract data type (for example, calling HashMap map is more efficient than calling map map). There is a high rate of misinformation, actually just about 6%. Moreover, after the JIT, they are directly not the most difference.

On devices that do not have a JIT, reading the cache domain is about 20% faster than reading the actual data directly. When there is a JIT, the domain reads and the local reads basically no difference. So optimization is not worth it unless you think it makes your code easier to read (which is also true for final, static, static final fields).

Method 11: Get the benchmark for performance tuning

Before you optimize, you should make sure that you are experiencing performance problems. You should make sure that you can accurately measure the current performance, otherwise you will not know whether the optimization is really effective.

All the techniques in this section require benchmark (benchmark) support. Benchmark can be found in code.google.com "Dalvik" project.

Benchmark was developed based on the Java version of the Caliper microbenchmarking framework. Microbenchmarking is difficult to do accurately, so caliper help you with this part of the work, and even help you to test the parts you did not expect to measure (because, the VM to help you manage the code optimization, you can hardly know how much of this optimization effect). We highly recommend using caliper to do your benchmark work.

We can also use TraceView to measure, but the measured data is not JIT-optimized, so the actual effect should be slightly better than the measured data.

Android app performance tuning tips

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.