Advanced Android (1) App performance optimization

Purpose and direction of performance optimization

The purpose of performance optimization is to make the application app faster, more stable & less expensive. The details are as follows:

  • Faster: The application runs more smoothly, does not freeze, and can quickly respond to user operations
  • More stable: the application can run stably & solve user needs, and there will be no application crash (Crash) and no response (ANR) problems during user use
  • More economical: save resource consumption, including memory usage, battery capacity, network resources, etc.

For the above purposes, the indicators for APP optimization are: fluency, stability, and resource saving.

The specific implementation is as follows:

insert image description here

fluency

To reduce problems such as stuttering and long response time during use, and to provide users with a smooth operation experience, it is mainly optimized for three aspects:

  • startup speed
  • page display speed
  • responding speed

startup speed

Reason for optimization: When loading the application for the first time, it needs to load a lot of resources or logic functions.

Optimization scheme: adopt strategies such as asynchronous loading (multi-threading), step-by-step loading, and deferred loading to reduce the loading tasks when starting the application, thereby improving the startup speed.

page display speed

Reason for optimization: There are too many contents (layouts or controls) to be drawn on the page, resulting in too long page measurement time; too low page drawing efficiency, resulting in too long drawing time.

Optimization scheme: layout optimization and drawing optimization

responding speed

Reason for optimization: ANR occurs in the application, which causes the application to respond slowly

Optimization solution: use multi-threading to execute a large number of time-consuming operations in worker threads.

Optimization scheme: use multi-threading, put a lot of time-consuming operations in worker threads, such as AsyncTask, HandlerThread, etc.

stability

There are many reasons that affect the stability of Android applications, mainly: application crash (Crash), application unresponsive (ANR)

ANR

ANR (Application Not Responding) appears in the program, causing the application to respond slowly or the screen to freeze on a page.

Common ANR reasons:

  • The application does not respond to user input events (keys or touches) within 5 seconds.
  • The broadcast receiver (BroadcastReceiver) did not complete the processing of related events within 10s.
  • The service (Service) cannot be processed within 20s.

Optimization scheme: use multi-threading, put a lot of time-consuming operations in worker threads, such as AsyncTask, HandlerThread, etc.

In actual development, when an ANR occurs in a process, the system will create a file traces.txt in the /data/anr directory, and the cause of the ANR can be located by analyzing the file

Crash

In many cases, the program crashes because of memory overflow or OOM.

The Android system allocates limited memory for each application. When there are many memory leaks and abnormal use of memory in the application, it is easy to cause the memory required by the application to exceed the memory limit that the system can allocate for it (OOM ), causing the program to crash.

To solve Crash is to solve OOM, and the work involved is memory optimization.

resource saving

Reason for optimization: Due to the limited hardware performance of mobile devices, it is very important to reduce the resource consumption of applications

Optimization direction: memory size, installation package size, power consumption & network traffic

The main means include: memory optimization, reducing the size of the installation package, reducing network traffic, and reducing application power consumption.
insert image description here

layout optimization

The quality of layout performance mainly affects the page display speed in Android. The essence of layout affecting performance lies in: page measurement and drawing time

Choose a layout that consumes less performance

  • Low-cost layout = simple function = FrameLayout、LinearLayout
  • Expensive layout = complex function =RelativeLayout

Reduce the level of layout (nesting)

  • Principle: less layout levels ->> less work for drawing ->> fast drawing speed ->> performance improvement
  • Optimization method: use layout label & choose layout type appropriately

Note: It is better to choose one layout with high cost performance than to nest multiple layouts with low cost performance

Use layout tags

Use the layout attribute wrap_content as little as possible

The layout attribute wrap_content will increase the calculation cost of layout measurement and should be used as little as possible; especially when the known width and height are fixed values, wrap_content should not be used.

include

The include> tag can refer to the layout of another layout in one layout. This is usually suitable for apps with complex interface layouts and shared layouts for different interfaces, such as the top layout, sidebar layout, and bottom tab bar layout of an app. The layout of each item of ListView and GridView, etc., extract the layouts used by multiple interfaces in the same APP and then refer to them through <include>tags, which can not only reduce the complexity of the layout, but also achieve layout reuse (when the layout is changed) Only one place needs to be modified).

merge

The merge tag is used to help reduce duplicate layouts in the view tree when one layout contains another layout.
The main points of merge use:

  • merge must be placed on the root node of the layout file
  • merge is not a ViewGroup, nor a View, it is equivalent to declaring some views, waiting to be added.
  • The merge tag is added under the A container, then all views under the merge will be added under the A container.
  • Because merge is not a View, it cannot set the label attribute, or it is invalid if it is set.
  • Because the merge tag is not a View, when the LayoutInflate.inflate method renders, the second parameter must specify a parent container, and the third parameter must be true, that is, a parent node must be specified for the view under merge.

Example:
without using merge:
layout1.xml

<FrameLayout>
   <include layout="@layout/layout2"/>
</FrameLayout>

layout2.xml

<FrameLayout>
   <TextView />
</FrameLayout>

actual effect:

<FrameLayout>
   <FrameLayout>
      <TextView />
   </FrameLayout>
</FrameLayout>

Use merge:
layout1.xml

<FrameLayout>
   <include layout="@layout/layout2"/>
</FrameLayout>

layout2.xml

<merge>
   <TextView />
</merge>

actual effect:

<FrameLayout>
   <TextView />
</FrameLayout>

The difference between include and merge

As can be seen from the above example, include actually embeds another layout completely where it needs to be used. Since all components must be in the ViewGroup, this leads to using the include tag. When embedding, there will be an additional layer of ViewGroup, and using merge is equivalent to declaring a virtual ViewGroup, so that it can be fully integrated into the merge when include to where it needs to be used.

ViewStub

ViewStup is a lightweight view. The reason why it is called a lightweight view is that it will not draw during page loading and rendering, but only when you need it.

The function of the ViewStub tag is for lazy loading of the layout. When the system encounters a ViewStub tag, it does not perform drawing processing (such as measure, layout, etc.), which is more efficient than setting the View to be hidden or invisible.

Benefits of using ViewStub:

  • It can avoid performance consumption such as view measure and layout corresponding to ViewStub, and it will only be executed when it is used, such as increasing the page display speed when the APP starts.
  • Compared with the usage of invisible and gone, when it is set to invisible, the view object will occupy the position, but the state is invisible, and the object will still be created, initialized, and occupy resources. If set to gone, the view does not occupy a position in the layout layout file, but the object will still be created, initialized, and occupy resources.

The disadvantage of ViewStub is that it cannot use tags, it is similar to tags <merge>in use<include>

memory leak

In terms of mechanism: Java has GC, and there should be no memory leaks. The reason for memory leaks is only external human reasons.Unconsciously holding object references such that the lifetime of the referrer > the lifetime of the referenced

Common causes of memory leaks

Adding elements to collections

Cause of memory leak: After the collection class adds elements, it still refers to the collection element object, which makes the collection element object not recyclable, resulting in a memory leak

// 通过 循环申请Object 对象 & 将申请的对象逐个放入到集合List
List<Object> objectList = new ArrayList<>();        
       for (int i = 0; i < 10; i++) {
    
    
            Object o = new Object();
            objectList.add(o);
            o = null;
        }
// 虽释放了集合元素引用的本身:o=null)
// 但集合List 仍然引用该对象,故垃圾回收器GC 依然不可回收该对象

Solution:
Since there are many elements in 1 collection, the easiest way = empty the collection object & set to null

// 释放objectList
objectList.clear();
objectList=null;

Static keyword modifier member

The life cycle of the member variables decorated with the Static keyword = the life cycle of the application.

Leakage reason: The member variable modified by the Static keyword refers to an instance that consumes too much resources (such as Context), and it is easy to have the life cycle of the member variable > the life cycle of the reference instance. When the reference instance needs to end the life cycle and be destroyed, Will not be recycled due to the holding of static variables, resulting in memory leaks

public class ClassName {
    
    
 // 定义1个静态变量
 private static Context mContext;
 //...
// 引用的是Activity的context
 mContext = context; 

// 当Activity需销毁时,由于mContext = 静态 & 生命周期 = 应用程序的生命周期,故 Activity无法被回收,从而出现内存泄露
}

solution:

  1. Try to avoid Static member variables referring to instances that consume too much resources (such as Context).
  2. Use weak references (WeakReference) instead of strong references to hold instances

non-static inner class / anonymous class

The non-static inner class holds a reference to the outer class, which prevents the outer class from being released.

Common situations are:

  • Create a static instance in a non-static inner class
  • Multi-threading: AsyncTask, etc., when the worker thread is processing the task, it holds a reference to the external class, causing the external class to fail to be GC
  • Message delivery mechanism: Handler, the Handler class holds a reference to an external activity. When there are unprocessed messages in the message queue, the Message in the message queue
    holds a reference to the Handler instance. This kind of reference dependency makes the Activity unable to be destroyed.

insert image description here

Resource object not closed after use

Leak reason: For the use of resources (such as broadcasting, file streaming, cursors for database operations, and image resource BitMap), if these resources are not closed or canceled in time when the Activity is destroyed, memory leaks will result.

Solution:
When the Activity is destroyed: close/logout resources in time

memory optimization

insert image description here

Guess you like

Origin blog.csdn.net/baiduwaimai/article/details/131019384