Android Code optimization Tips

Source: Internet
Author: User
Tags integer division

This article mainly introduces some small details of the optimization techniques, when these tips are used in combination, for the overall performance of the app is still useful, but can not significantly improve performance. Choosing the right algorithm and data structure should 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 rules:

    • Don't do redundant work.
    • If you can avoid, try not to allocate memory

One of the hardest issues to solve when optimizing apps is getting apps to run on all types of devices. Different versions of virtual machines will run at different speeds on different processors. You can't even simply think that "device x is at the speed of device y," and then use this multiple relationship to speculate on other devices. In particular, the speed of operation on the simulator is not related to the speed of the actual device. Similarly, the device has no JIT (instant compilation, translator note) also has a significant impact on the speed of operation: In the case of JIT optimization code is not necessarily in the absence of JIT optimization.

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.

Avoid creating unnecessary objects

Creating objects has never been a cost-free. The generational garbage collector in the thread allocation pool can make the allocation of temporary objects cheaper, but allocating memory is always more expensive than unallocated.

As you assign more objects to the app, you may need to force GC (garbage collection, translator) to do a little decompression for the user experience. The concurrent GC introduced in Android 2.3 will help you do this, but after all, unnecessary work should be avoided as much as possible

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

    • 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 signature and implementation to avoid direct connection operation, you should do this by creating a temporary object.
    • When extracting a string from the input dataset, try to return the substring object of the original data instead of creating a duplicate object. You will be new to a String object, but it should be shared internally with the original data char[] (at the cost if you just use a fraction of the original data, you just need to save this small portion of the object in memory)

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

    • 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 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.

Choose static instead of virtual

If you do not need to access the domain of an object, make sure that the method is static, 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.

Constants declared as static Final

Consider the way the following statement

The compiler uses a function that initializes the class, and then executes when the class is used for the first time. This function stores 42 intVal and extracts references from the class file's constant table strVal . When they are used intVal or later strVal , they are directly queried.

We can use final keywords to optimize:

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 is called intVal uses 42 directly, and the calling strVal code uses a relatively inexpensive "string constant" directive rather than a table-check.

Note: This optimization method is valid only for the original type and string type, not for any reference type. However, it is a good habit to use it when necessary static final .

Avoid 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 a bad 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.

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 (iterators, translator notes) are allocated for For-each calls 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.

Please compare the following three loops:

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 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 ().

You can also refer to the 46th article of the book "Effective Java" from Josh Bloch.

Private access using package-level access instead of internal classes

Refer to the following section of 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 = 27;         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 Foo because Foo$Inner of and are different classes, it is considered Foo$Inner illegal to access the Foo private members of the class directly. Even though the Java language allows internal classes to access private members of external classes. To get rid of this discrepancy, the compiler produces some imitation functions:

/*package*/ static int Foo.access$100(Foo foo) {     return foo.mValue; } /*package*/ static void Foo.access$200(Foo foo, int 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.

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 the case of desktop, space is not a problem, you should use double.

Similarly, for integer types, some processors implement multiplication of hardware several times, but no division. At this point, the integer division and the remainder are implemented within the software, which you should consider when you use a hash table or a large number of transfusion operations.

Using 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: In the Android API String.indexOf() , Dalvik is replaced for inline performance considerations. 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.

See the 47th article of the book "Effective Java" by Josh Bloch.

Use the native function with caution

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

See the 54th article of the book "Effective Java" by Josh Bloch.

About the error of performance

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, HashMap map a call is Map map more efficient than a call). 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).

About measurement

Before you optimize, you should decide 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 is based on the Java version of the calipermicrobenchmarking (baseline micro-measurement, translator note) 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 Code optimization Tips

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.