Android performance, the most comprehensive analysis of memory optimization

foreword

With the development of technology, the hardware configuration of smartphones is getting higher and higher. However, compared with the current PC, its computing power, battery life, storage space, etc. are still greatly limited. Much higher than desktop applications for PCs. The above reasons are enough to require developers to concentrate more on implementing and optimizing your code. Choosing the right algorithm and data structure is always the first thing developers should consider. At the same time, we should always keep in mind the two basic principles of writing efficient code: (1) Don't do unnecessary things; (2) Don't allocate unnecessary memory.

I have been in contact with Android development since last year. The following is a combination of my own project experience, and referring to Google's optimization documents and the opinions given by many technical experts on the Internet to sort out this document.

Scan the QR code below to get all documents for free

1. Memory optimization

The Android system limits the RAM space that each software can use (for example: Nexus one has a memory limit of 24M for each software), and the Java language itself consumes memory, and the dalvik virtual machine also occupies a certain amount of memory space. Therefore, the rational use of memory demonstrates the quality and skills of a programmer.

1) Understand JIT

Just-in-time Compilation (JIT), also known as Dynamic Translation, is a technology that improves the performance of bytecode compiled languages ​​by translating bytecode into machine code at runtime. The two runtime theories in the early stage of just-in-time compilation are bytecode compilation and dynamic compilation. Android's original Dalvik virtual machine is implemented as an interpreter, and the new version (Android2.2+) will be replaced by a JIT compiler. Performance tests show that the new version is about 6 times faster than the old version in multiple tests.

For details, please refer to http://hi.baidu.com/cool_parkour/blog/item/2802b01586e22cd8a6ef3f6b.html

2) Avoid creating unnecessary objects

Just like there is no free lunch in the world, there is no free object in the world. Although gc has established a temporary object pool for each thread, which can make the cost of creating objects smaller, the cost of allocating memory is always greater than that of not allocating memory. If you allocate object memory in the user interface loop, it will trigger periodic garbage collection, and the user will feel that the interface is hiccupping. Therefore, instances of best-effort objects should be avoided unless necessary. The following example will help you understand this principle: When you intercept a string from user-input data, try to use the substring function to obtain a substring of the original data instead of creating another copy of the substring. 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, then please change the parameters and implementation of the function to append the result directly to the StringBuffer instead of creating another Short-lived temporary objects.

A more extreme example is to split a multidimensional array into multiple 1D arrays:

Int arrays are better than Integer arrays, which also summarizes a basic fact that two parallel int arrays perform much better than (int, int) object arrays. Likewise, this works for all combinations of primitive 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 more efficient than (Foo,Bar) arrays. (There are exceptions, that is, when you create an API and let others call it. At this time, you should pay attention to the design of the API interface and sacrifice a little speed. Of course, inside the API, you still need to improve the code as much as possible. s efficiency)

In general, avoid creating short-lived temporary objects. Reducing object creation reduces garbage collection, which in turn reduces the impact on user experience.

3) Static method instead of virtual method

If you don't need to access the fields of an object, setting the method as static will speed up the call by 15% to 20%. This is also a good practice, because you can tell from the method declaration that calling the method does not need to update the state of this object.

4) Avoid internal Getters/Setters

In native languages ​​like C++, it is common practice to use Getters (i=getCount()) instead of direct field access (i=mCount). This is a good practice in C++ because the compiler will inline these accesses, and you can add code at any time if you need to constrain or debug accesses to these fields. And in Android, this is not a good practice. Virtual method calls are much more expensive than direct field access. In general, according to the practice of object-oriented languages, it makes sense to use Getters and Setters in public interfaces, but direct access is better in a class whose fields are frequently accessed. Without JIT, direct field access is about 3 times faster than calling getter access. With JIT (direct field access overhead is equivalent to local variable access), it is 7 times faster.

5) Cache members locally

Accessing member variables is much slower than accessing local variables, the following piece of code:

for(int i =0; i <this.mCount; i++)  {
dumpItem(this.mItems);
}

It is better to change it to this:

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

Another similar principle is: never call any method in the second condition of for. As shown in the following method, the getCount() method will be called every time the loop is executed, which is much more expensive than saving the result in an int first.

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

Similarly, if you want to access a variable multiple times, it is best to create a local variable for it first, for example:

protected void drawHorizontalScrollBar(Canvas canvas, int width, int height) {
if(isHorizontalScrollBarEnabled()) {
intsize = mScrollBar.getSize(false);
if(size <=0) {
       size = mScrollBarSize;
}
mScrollBar.setBounds(0, height - size, width, height);
mScrollBar.setParams(computeHorizontalScrollRange(), computeHorizontalScrollOffset(), computeHorizontalScrollExtent(),false);
mScrollBar.draw(canvas);
}
} 

There are 4 accesses to the member variable mScrollBar. If it is cached locally, the 4 member variable accesses will become 4 more efficient stack variable accesses.

In addition, method parameters have the same efficiency as local variables.

1) Use the static final modifier for constants

Let's take a look at these two declarations that precede the class:

static int intVal = 42;
static String strVal = "Hello, world!";

It must generate a method called clinit to initialize the class, which will be executed when the class is used for the first time. The method will assign 42 to intVal, and then assign a reference to the constant table in the class to strVal. When these values ​​are used later, they will be looked up in the member variable table. Let's improve it a bit, using the "final" keyword:

static final int intVal = 42;
static final String strVal = "Hello, world!";  
  
现在,类不再需要clinit方法,因为在成员变量初始化的时候,会将常量直接保存到类文件中。用到intVal的代码被直接替换成42,而使用strVal的会指向一个字符串常量,而不是使用成员变量。

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

You can also declare local variables as final, again, this will not bring about a performance increase. Using "final" can only make local variables look clearer (but sometimes this is necessary, such as when using anonymous inner classes).

2) Use the improved For loop syntax

An improved for loop (sometimes called a for-each loop) can be used with collections and arrays that implement the iterable interface. In collection classes, iterators have the interface call hasNext() and next() methods. In ArrayList, the hand-written counting loop iteration is 3 times faster (with or without JIT), but in other collection classes, the improved for loop syntax and iterator have the same efficiency. The following shows how to access arrays collectively:

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

In zero(), each loop accesses the static member variable twice and obtains the length of the array once.

In one(), store all member variables into local variables.

two() uses the foreach syntax introduced in java1.5. The compiler will save a reference to the array and the length of the array into a local variable, which is great for accessing array elements. But the compiler will also generate an additional storage operation for local variables (access to variable a) in each loop, which will be 4 bytes more than one(), and the speed is slightly slower.

3) Avoid floating point numbers

A general rule of thumb is that on Android devices, floating point numbers are twice as slow as integers, and this is true on the G1 without the FPU and JIT vs. the Nexus One with the FPU and JIT (the difference in absolute speed of arithmetic operations between the two devices about 10 times) Speed-wise, there is no difference between float and double on modern hardware. More broadly speaking, double is 2 times larger. On desktops, double has higher priority than float because of the absence of space issues. But even for integers, some chips have hardware multiplication but lack division. In this case, integer division and modulo operations are implemented by software, just like when you design a Hash table or do a lot of arithmetic, for example, a/2 can be replaced by a*0.5.

4) Understand and use class libraries

Choosing code in the library rather than rewriting it yourself, besides the usual reasons, considers that the library method will be replaced by assembly code calls when the system is idle, which may be better than the equivalent best Java code generated in the JIT .

       i.    当你在处理字串的时候,不要吝惜使用String.indexOf(),String.lastIndexOf()等特殊实现的方法。这些方法都是使用C/C++实现的,比起Java循环快10到100倍。

       ii.    System.arraycopy方法在有JIT的Nexus One上,自行编码的循环快9倍。

       iii.    android.text.format包下的Formatter类,提供了IP地址转换、文件大小转换等方法;DateFormat类,提供了各种时间转换,都是非常高效的方法。

For details, please refer to http://developer.android.com/reference/android/text/format/package-summary.html

       iv.    TextUtils类

For string processing, Android provides us with a simple and practical TextUtils class. If you do not need to think about regular expressions when dealing with relatively simple content, you may try this class in android.text.TextUtils. For details, please refer to http://developer . android.com/reference/android/text/TextUtils.html

        v.    高性能MemoryFile类。

Many people complain that Android's underlying I/O performance is not ideal. If you don't want to use NDK, you can use the MemoryFile class to achieve high-performance file read and write operations. Where is MemoryFile suitable for? For I/O that requires frequent operations, mainly I/O operations related to external storage, MemoryFile maps the files on the NAND or SD card to the memory for modification and processing, thus replacing them with high-speed RAM ROM or SD card, the performance is naturally improved a lot, and the power consumption is also reduced for Android phones. There are not many functions implemented by this class. It is directly inherited from Object and executed directly at the bottom of C through JNI.

For details, please refer to http://developer.android.com/reference/android/os/MemoryFile.html

Here, only a few commonly used classes and methods are simply listed, and more depends on the usual accumulation and discovery. It is beneficial to read more help documents given by Google.

5) Reasonable use of local methods

Native methods are not necessarily more efficient than Java. At the very least, the association between Java and native is consuming, and JIT cannot optimize it. When you allocate native resources (memory on the native heap, file descriptors, etc.), it is often difficult to reclaim these resources in real time. At the same time you also need to compile your code in various structures (rather than relying on JIT). It may even be necessary to compile different versions for the same architecture: native code compiled for GI on an ARM processor won't take full advantage of ARM on the Nexus One, and native code compiled for ARM on the Nexus One won't work on ARM on the G1 run on. Native code is especially useful when you want to deploy programs to the Android platform where there is a native code library, not for speeding up Java applications.

6) Complicated algorithms should be completed in C as much as possible

Complicated algorithms should be completed in C or C++ as much as possible, and then called with JNI. But if the algorithm is relatively simple, there is no need to be so troublesome. After all, JNI calls will also take a certain amount of time. Please weigh.

7) Reduce unnecessary global variables

Try to avoid static member variables referencing instances that consume too much resources, such as Context. Android provides a very sound message passing mechanism (Intent) and task model (Handler), which can prevent some unnecessary global variables by means of passing or events.

8) Don't count too much on gc

Java's gc uses a directed graph. To judge whether an object is valid, it depends on whether other objects can reach the vertex of this object. Compared with linked lists and binary trees, the overhead of directed graphs is conceivable. So don't count too much on gc. Objects that will not be used can point to NULL, and pay attention to code quality. At the same time, it is displayed to let the system gc recycle, for example, when processing pictures,

if(bitmap.isRecycled()==false) { //如果没有回收
     bitmap.recycle();
}

9) Understand the four reference methods of Java

Starting with JDK 1.2, object references are divided into four levels, so that programs can more flexibly control the life cycle of objects. These 4 levels from high to low are: strong reference, soft reference, weak reference and phantom reference.

                 i.    强引用(StrongReference)

Strong references are the most commonly used references. If an object has strong references, the garbage collector will never collect it. When the memory space is insufficient, the Java virtual machine would rather throw an OutOfMemoryError error, causing the program to terminate abnormally, and would not solve the problem of insufficient memory by arbitrarily recycling objects with strong references.

                 ii.    软引用(SoftReference)

If an object has only soft references, the memory space is sufficient, and the garbage collector will not reclaim it; if the memory space is insufficient, the memory of these objects will be reclaimed. As long as the garbage collector does not collect it, the object can be used by the program. Soft references can be used to implement memory-sensitive caches.

               iii.    弱引用(WeakReference)

In the process of scanning the memory area under its jurisdiction by the garbage collector thread, once an object with only weak references is found, its memory will be reclaimed regardless of whether the current memory space is sufficient or not. However, since the garbage collector is a very low-priority thread, objects that only have weak references may not be found quickly.

                iv.    虚引用(PhantomReference)

As the name suggests, it is useless. Unlike other types of references, phantom references do not determine the lifetime of an object. If an object holds only phantom references, it is as if it has no references and may be reclaimed by the garbage collector at any time. Understanding and proficiently mastering these 4 reference methods and choosing the appropriate object application method are very helpful for memory recovery.

For details, please refer to http://blog.csdn.net/feng88724/article/details/6590064

10) Use Entity Classes Over Interfaces

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

Map map1 = new HashMap();
HashMap map2 = new HashMap();

Which is better?

According to the traditional point of view, Map will be better, because you can change his concrete implementation class, as long as this class inherits from the Map interface. The traditional view is true for traditional programs, but it is not suitable for embedded systems. Calling a reference to an interface will take twice as long as calling a reference to an entity class. If HashMap is perfectly suitable for your program, then there is little value in using Map. If you are not sure about some places, avoid using Map first, and leave the rest to the refactoring function provided by the IDE. (of course the public API is an exception: a good API often sacrifices some performance)

11) Avoid using enums

Enum variables are very convenient, but unfortunately it sacrifices execution speed and increases file size considerably. For example:

public class Foo {
       public enum Shrubbery { GROUND, CRAWLING, HANGING }
}

Will produce a 900-byte .class file (Foo S hubbery .class). When it is called for the first time, this class calls the initialization method to prepare each enumeration variable. Each enumeration item will be declared as a static variable and assigned a value. Then put these static variables in a class called "Shubbery.class). When it is called for the first time, this class will call the initialization method to prepare each enumeration variable. Each enumeration item will be declared as a static variable, and is assigned a value. These static variables are then placed in a file called "S h u bb ery . c l a ss ) . When it is called for the first time, this class calls the initialization method to prepare each enumeration variable. Each enumeration item will be declared as a static variable and assigned a value. These static variables are then placed in a static array variable called " VALUES". And such a large amount of code is just to use three integers.

This way: Shrubbery shrub = Shrubbery.GROUND; will cause a reference to a static variable, if the static variable is final int, then the compiler will directly inline this constant.

On the one hand, using enum variables can make your API more elegant and provide compile-time checking. So in general you should definitely choose enum variables for public APIs. But when performance is limited, you should avoid this approach.

In some cases, it is better to use the ordinal() method to obtain the integer value of the enumeration variable, for example:

for(int n =0; n < list.size(); n++) {
       if(list.items\[n\].e == MyEnum.VAL\_X) {
              // do something
       } else if(list.items\[n\].e == MyEnum.VAL\_Y) {
              // do something
       }
}

Replace with:

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++) {
       intvalItem \= items\[n\].e.ordinal();
       if(valItem == valX) {
              // do something
       } else if(valItem == valY) {
              // do something
       }
}

There will be some improvement in performance, but this is not the final solution.

12) In private internals, consider replacing private access with package access

public class Foo {
           public class Inner {
                public 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:"+value);
           }
}

The key thing to note is that we define a private inner class (Foo Inner ), which directly accesses a private method and private variable in the outer class. This is legal, and the code also prints " Valueis 27 " as expected. But the problem is that the virtual machine thinks that from Foo Inner), directly access a private method and private variable in the outer class. This is legal, and the code prints "Value is 27" as expected. But the problem is, the virtual machine thinks that from FooInn er ) , directly access a private method and private variable in the outer class. This is legal, and the code also prints " Val u e i s 27 " as expected . But the problem is that the virtual machine thinks that it is illegal to directly access the private members of Foo from Foo Inner, because they are two different classes . An integrated approach to bridge these gaps.

/\*package\*/static int Foo.access$100(Foo foo) {
return foo.mValue;
}
/\*package\*/static void Foo.access%200(Foo foo,int value) {
       foo.duStuff(value);
}

The inner class will call these static methods anywhere in the outer class that needs to access the mValue field or call the doStuff method. This means that the code treats direct access to member variables as if they were accessed through accessor methods. I mentioned earlier how accessor access is slower than direct access, and this example shows that certain language conventions lead to invisible performance problems. If you use these codes in high-performance Hotspot, you can declare the fields and members accessed by inner classes as package access rights, rather than private. But this also means that these fields will be accessed by other classes in the same package, so it should not be used in public API.

13) Declare variables used with inner classes at package scope

Take a look at the class definition below:

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 an inner class (Foo Inner ) that needs to access the private domain variables and functions of the outer class. This is legal, and will print the expected value Valueis 27 . The problem is that technically speaking (behind the scenes) Foo Inner), it needs to access private domain variables and functions of the outer class. This is legal and will print the expected value of Value is 27 . The problem is that technically speaking (behind the scenes) FooIn n er ) , it needs to access the private domain variables and functions of the outer class. This is legal and will print the desired result Val u e i s 27 . The problem is that technically speaking (behind the scenes) Foo Inner is a completely separate class, and it is illegal for it to directly access Foo's private members. To bridge this gap, the compiler needs to 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);
}

These static methods are called every time the inner class accesses the mValueg and gdoStuffg methods. That is to say, the above code illustrates a problem, you are accessing these member variables and functions through interface methods instead of calling them directly. As we have said before, using interface methods (getters, setters) is slower than direct access. So this example is an "invisible" performance obstacle created under the specific syntax. We can avoid this problem by changing the variable and function declarations accessed by inner classes from private scope to package scope. Doing so makes the code run faster and avoids creating extra static methods. (Unfortunately, these fields and methods can be directly accessed by other classes in the same package, which is against the classic OO principles. So you should use this optimization principle carefully when designing public APIs).

14) Cache

Use the cache in moderation, do not overuse, because the memory is limited, do not store image data if you can save the path address, try not to cache the ones that are not used frequently, and clear them when not in use.

15) Close the resource object

For SQLiteOpenHelper, SQLiteDatabase, Cursor, files, I/O operations, etc., you should remember to show off.

2. View optimization

1) View optimization

                   i.    减少不必要的View以及View的嵌套层次。

For example, to implement a layout commonly used in listview, you can use RelativeLayout to reduce nesting. You must know that each View object will consume 1~2k of memory, and too many nesting levels will cause frequent gc, resulting in ANR.

                 ii.    通过HierarchyViewer查看布局结构

Use HierarchyViewer to view the structure of View: ~/tools/hierarchyviewer, you can clearly see the flat structure under RelativeLayout, which can speed up the rendering speed of dom.

For details, please refer to http://developer.android.com/guide/developing/tools/hierarchy-viewer.html

               iii.    通过Layoutopt优化布局

Use the layoutopt command in the tools directory of the Android sdk to check whether your layout needs to be optimized. For details, please refer to http://apps.hi.baidu.com/share/detail/34247942

2) Multithreading solves complex calculations

Data operations that take up more CPU should be performed in a separate thread as much as possible, and the execution results will be displayed on the UI thread through handlers and other methods. Especially for network access, database query, and complex algorithms. Currently Android provides a combination of AsyncTask, Hanlder, Message and Thread. For multi-thread processing, if there are many concurrent threads and frequent creation and release at the same time, the efficiency bottleneck of thread creation can be solved through the thread pool of the concurrent class. It is also worth noting that when customizing the View in application development, the interactive part must not be written as a thread to continuously refresh the interface display, but actively trigger the update of the interface according to the TouchListener event.

3) Layout is done in Java faster than XML

Under normal circumstances, the Android program layout is often written in XML files, which can improve development efficiency, but considering the security and execution efficiency of the code, it can be created through Java code execution. Although the XML compiled by Android is binary, it can be loaded The efficiency of the XML parser still takes up a lot of resources. The processing efficiency of Java is much faster than that of XML, but for the writing of a complex interface, some nesting considerations may be required. If you are flexible in thinking, use Java code to layout your The Android app is a better way.

4) Scale large images

Picture reading is a frequent visitor to OOM (Out of Memory). When reading 4M pictures directly on an Android mobile phone, the god of death will usually come, so often the photos taken by your mobile phone cannot be directly read. We often use the BitmapFactory class when scaling and processing large pictures. The size of the stack for pictures in the virtual machine when reading the bitmap Bitmap in the android system is only 8M. This error is sometimes encountered when decoding a picture with BitmapFactory. This is often caused by an image that is too large. At this time we need to allocate less memory space for storage. BitmapFactory.Options.inSampleSize Setting proper inSampleSize can make BitmapFactory allocate less space to eliminate this error. Android provides a dynamic calculation, as follows:

Check the size of the image before reading it:

BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds \= true;
Bitmap bitmap \= BitmapFactory.decodeFile(imageFile, opts);

Use the original width and height of the obtained picture to calculate the smaplesize suitable for you

BitmapFactory.Options opts = new BitmapFactory.Options();
 opts.inSampleSize \= 4 ;// 4就代表容量变为以前容量的1/4
 Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);             

For outdated Bitmap objects, be sure to recycle in time, and assign this object to null.

bitmap.recycle();
bitmap \= null; 

5) Reasonable use of ViewStub

ViewStub is a hidden view object that does not occupy memory space, and it can delay loading layout resource files at runtime. This layout resource file will only be loaded when the ViewStub is visible or the inflate() function is called. This ViewStub replaces itself in the parent container when the view is loaded. Therefore, the ViewStub will always exist in the view until setVisibility(int) or inflate() is called. The layout parameters of the ViewStub will be added to the ViewStub parent container along with the number of loaded views. Similarly, you can also define or rename the Id value of the view object to be loaded by using the inflatedId property. So we can use ViewStub to delay loading some more complex layouts, dynamically load View, and use ViewStub to avoid some infrequent views holding references for a long time.

For details, please refer to http://developer.android.com/reference/android/view/ViewStub.html

6) Performance optimization for ListView

                i.    复用convertView。

                ii.    在getItemView中,判断convertView是否为空,如果不为空,可复用。如果couvertview中的view需要添加 listerner,代码一定要在if(convertView==null){}之外。

               iii.    异步加载图片,item中如果包含有web image,那么最好异步加载。

                iv.    快速滑动时不显示图片

When the list is scrolled quickly (SCROLL_STATE_FLING), the pictures in the item or the views that need to consume resources may not be displayed; while in the other two states (SCROLL_STATE_IDLE and SCROLL_STATE_TOUCH_SCROLL), those views will be displayed.

                  v.    item尽可能的减少使用的控件和布局的层次;背景色与cacheColorHint设置相同颜色;ListView中item的布局至关重要,必须尽可 能的减少使用的控件,布局。             RelativeLayout是绝对的利器,通过它可以减少布局的层次。同时要尽可能的复用控件,这样可以减少 ListView的内存使用,减少滑动时gc次数。ListView的背景色与cacheColorHint设置相同颜色,可以提高滑动时的渲染性能。

                  vi.    getView优化

The performance of getView in ListView is the key, and it should be optimized as much as possible here. The view should be reused in the getView method; complex logic calculations cannot be done in the getView method, especially database and network access operations, otherwise it will seriously affect the performance of sliding. The optimization looks like this:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
       Log.d("MyAdapter", "Position:" + position + "---" + String.valueOf(System.currentTimeMillis()));
       final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT\_INFLATER\_SERVICE);
       View v \= inflater.inflate(R.layout.list\_item\_icon\_text, null);
       ((ImageView) v.findViewById(R.id.icon)).setImageResource(R.drawable.icon);
       ((TextView) v.findViewById(R.id.text)).setText(mData\[position\]);
       return v;
}

It is recommended to change to:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
       Log.d("Adapter", "Position:" + position + " : " + String.valueOf(System.currentTimeMillis()));
       ViewHolder holder;
       if (convertView == null) {
              final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT\_INFLATER\_SERVICE);
              convertView \= inflater.inflate(R.layout.list\_item\_icon\_text, null);
              holder \= new ViewHolder();
             holder.icon \= (ImageView) convertView.findViewById(R.id.icon);
             holder.text \= (TextView) convertView.findViewById(R.id.text);
             convertView.setTag(holder);
       } else {
             holder \= (ViewHolder) convertView.getTag();
       }
              holder.icon.setImageResource(R.drawable.icon);
              holder.text.setText(mData\[position\]);
              return convertView;
       }
 
       static class ViewHolder {
               ImageView icon;
               TextView text;
       }
}

The above are the optimization suggestions given at the Google IO conference. After trying, ListView is indeed much smoother. Using 1000 records, the first method takes 25211ms after testing, and the second method takes 16528ms.

7) other

               i.    分辨率适配

-ldpi, -mdpi, -hdpi are configured with different precision resources, and the system will adapt itself according to the device, including drawable, layout, style and other different resources.

               ii.    尽量使用dp(density independent pixel)开发,不用px(pixel)。

               iii.    多用wrap\_content, fill\_parent

               iv.    抛弃AbsoluteLayout

               v.    使用9patch(通过~/tools/draw9patch.bat启动应用程序),png格式

               vi.    采用<merge> 优化布局层数;采用<include >来共享布局。

               vii.    将Acitivity中的Window的背景图设置为空。getWindow().setBackgroundDrawable(null);android的默认背景是不是为空。

               viii.    View中设置缓存属性.setDrawingCache为true。

3. Network optimization

1) Avoid frequent network requests

When accessing the server, it takes more time to establish a connection than to transmit. If it is not necessary, do not divide the things that can be done in one interaction into multiple interactions (this needs to be coordinated with the server). Effective management of Service The background service is equivalent to a continuously running Acitivity. If the developed program background will have a service to update the data on the server continuously, and let it sleep when the data is not updated, this method consumes a lot of power , usually, you can use AlarmManager to start the service regularly. As shown below, execute once every 30 minutes.

AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM\_SERVICE);
Intent intent \= new Intent(context, MyService.class);
PendingIntent pendingIntent \= PendingIntent.getService(context, 0, intent, 0);
long interval = DateUtils.MINUTE\_IN\_MILLIS \* 30;
long firstWake = System.currentTimeMillis() + interval;
am.setRepeating(AlarmManager.RTC,firstWake,  interval,  pendingIntent);

2) Data compression

The transmitted data is compressed. At present, most websites support GZIP compression. Therefore, when downloading large amounts of data, try to use GZIP to download, which can reduce network traffic, which is generally about 30% of the data size before compression.

HttpGet request = new HttpGet("http://example.com/gzipcontent");
HttpResponse resp \= new DefaultHttpClient().execute(request);
HttpEntity entity \= response.getEntity();
InputStream compressed \= entity.getContent();
InputStream rawData \= new GZIPInputStream(compressed);

3) Use thread pool

The thread pool is divided into a core thread pool and a common thread pool. Time-consuming tasks such as downloading pictures are placed in the common thread pool to avoid time-consuming tasks blocking the thread pool and causing all asynchronous tasks to wait.

4) Select the appropriate data format transmission form

**[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oPIvXD8W-1681723593584)(null)]**

Among them, Tree Parse is DOM parsing Event/Stream is SAX parsing.

Obviously, the parsing efficiency is higher by using streams, because DOM parsing is organized according to the node hierarchy after reading the entire document. The streaming method is to read data while parsing. After the data is read, the parsing is complete. In terms of data format, JSON and Protobuf are significantly more efficient than XML, and everyone is familiar with XML and JSON. From the above figure, it can be concluded that SAX and other methods of reading and parsing should be used as much as possible to parse the data. For mobile devices, it is better to use lightweight data formats such as JSON.

1) other

Set the connection timeout and response timeout. Http requests are divided into whether they can be cached or not according to business requirements. In an environment without a network, some data can still be browsed through the cached HttpResponse to realize offline reading.

2. Database related

1) Compared with the encapsulated ContentProvider, the execution efficiency of the original SQL statement is high, such as the execution efficiency of rawQuery and execSQL is relatively high.

2) When you need to modify multiple data at one time, you can consider using SQLite's transaction mode for batch processing.

3) Insert multiple rows of data in batches using the InsertHelper or bulkInsert method

4) For those that can use file operations, use file operations as much as possible. The speed of file operations is about 10 times faster than database operations.

3. Performance testing

For performance testing of software on the Android platform, the following methods can be used to analyze efficiency bottlenecks. At present, Google has introduced a variety of testing toolkits in the Android software development process, such as Unit test engineering, debugging classes, and simulator Dev. Tools can directly reflect the execution performance.

  1.   在模拟器上的Dev Tools可以激活屏幕显示当前的FPS,CPU使用率,可以帮助我们测试一些3D图形界面的性能。
    
  2.   一般涉及到网络应用的程序,在效率上和网速有很多关系,这里需要多次的调试才能实际了解。
    
  3.   对于逻辑算法的效率执行,我们使用Android上最普遍的,计算执行时间来查看:
    
long start = System.currentTimeMillis();
// do something
long duration = System.currentTimeMillis() - start;

The final duration holds the number of milliseconds it takes to actually process the method.

  1.   gc效率跟踪,如果你执行的应用比较简单,可以在DDMS中查看下Logcat的VM释放内存情况,大概模拟下那些地方可以缓存数据或改进算法的。
    
  2.   线程的使用和同步,Android平台上给我们提供了丰富的多任务同步方法,但在深层上并没有过多的比如自旋锁等高级应用,不 过对于Service和 appWidget而言,他们实际的产品中都应该以多线程的方式处理,以释放CPU时间,对于线程和堆内存的查看这些都可以在DDMS中看到。
    
  3.   利用traceview和monkey等工具测试应用。
    
  4.   利用layoutopt和ninepatch等工具优化视图。
    

4 Conclusion

This article gives some common optimization methods in Android mobile development. In most cases, the optimized code using these optimization methods has a significant improvement in execution efficiency and memory overflow. In actual application, the optimization of the program must be weighed whether it is necessary, because optimization may bring adverse effects such as increasing BUG, ​​reducing the readability of the code, and reducing the portability of the code. I hope you don't optimize blindly, please make sure there are problems before optimizing. And you know the performance of the current system, otherwise it is impossible to measure the performance improvement you get from trying. I hope this article can really help you. We welcome further exchanges on the above issues. If you find any mistakes or deficiencies, please correct them.

Guess you like

Origin blog.csdn.net/m0_56255097/article/details/130205091