Android performance tuning

http://my.oschina.net/jerikc/blog/139051This

article mainly shares its performance tuning advantages in the appstore project, including synchronous to asynchronous, caching, layout optimization, database optimization, algorithm optimization, delayed execution, etc.
1. Performance bottleneck point
The entire page is mainly composed of ViewPager of 6 Pages, each Page is a GridView, and one screen of GridView roughly displays 4*4 item information (there is a picture at the end of this article). Due to the acquisition of more network data and the need to maintain the app download progress and status on the page at any time, the following performance problems occur:
a. ViewPager sliding left and right is obviously stuck
b. GridView scrolling up and down is obviously stuck
c. Other activities return to ViewPager Activity slowlyd
. The speed of network acquisition and display is slow.


2. Performance debugging and positioning
: Traceview, monkey, monkey runner are mainly used for debugging. Traceview is similar to visualvm for java web tuning. The usage method is as follows: Add android.os
to the activity onCreate function that needs to be tuned .

debug.startMethodTracing("Entertainment"); Add android.os.debug.stopMethodTracing() ;
to the onDestrory function



After the program exits, the file Entertainment.trace will be generated in the root directory of the sd card, cmd to the tools directory of the android sdk and run traceview.bat Entertainment.trace, the screenshot below shows the

traceview

from which you can see the calling time and number of calls of each function , average call time, time occupancy percentage, etc. to locate time-consuming operations. For more details on monkey and monkey runner, please refer to the following blog introduction.


3. The advantages of performance tuning
mainly include synchronization to asynchronous, caching, layout optimization, database optimization, algorithm optimization, and delayed execution.
1. Synchronous to asynchronous
This does not need to say more, time-consuming operations are executed in threads to prevent occupying the main thread, and solve anr to a certain extent.
But you need to pay attention to the combination of thread and service (to prevent the thread from being recycled after the activity is recycled) and the number of threads (optimization introduced later)
PS: Please use the java thread pool (introduced later), and use AsyncTask less, because AsyncTask has performance problems ( It will be introduced in a separate blog post in the future)


2. It takes time to allocate resources to create objects in cached
java, and the more objects created, the more frequent gc will affect the system response. Mainly use singleton mode, cache (image cache, thread pool, View cache, IO cache, message cache, notification bar notification cache) and other methods to reduce object creation.
(1). Singleton mode This method can be used for classes with high cost
to create, to ensure that there is one instance globally, and the class will not generate overhead due to the creation of additional objects during program operation. The sample code is as follows: Singleton

pattern:

class Singleton {
    private static Singleton instance = null;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}


(2). The cache is used in the
program Image cache, thread pool, View cache, IO cache, message cache, notification bar notification cache, etc.
a. Image cache: see ImageCache and ImageSdCache


b. Thread pool: Use Java's Executors class to provide four different types of thread pools through newCachedThreadPool, newFixedThreadPool, newSingleThreadExecutor, newScheduledThreadPool


c. View cache:

listView's getView cache:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.type_item, null);
        holder = new ViewHolder();
        holder.imageView = (ImageView)convertView.findViewById(R.id.app_icon);
        holder.textView = (TextView)convertView.findViewById(R.id.app_name);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder)convertView.getTag();
    }
    holder.imageView.setImageResource(R.drawable.index_default_image);
    holder.textView.setText("");
    return convertView;
}

/**
* ViewHolder
*/
static class ViewHolder {

    ImageView imageView;
    TextView textView;
}
Reduce the number of layout inflates by whether convertView is null, and reduce the number of findViewByIds by static ViewHolder. These two functions, especially inflate, are quite time-consuming.


d. IO caching:
use an input stream with a caching strategy, instead of BufferedInputStream InputStream, BufferedReader replaces Reader, BufferedReader replaces BufferedInputStream. Applicable to both file and network IO.


e. Message cache: Recycle the message object through the Handler's obtainMessage, reducing the cost of creating the Message object
handler.sendMessage(handler.obtainMessage(1));


f. Notification bar notification cache: The status of the notification bar progress bar needs to be changed continuously during the download , If you continue to create a new Notification, the notification bar will be very stuck. Here we can use the simplest cache
Map<String, Notification> notificationMap = new HashMap<String, Notification>(); if the notificationMap does not exist, create a new notification and put it into map.


(3). Others
can create base classes to solve The problem is not to use specific subclasses: except for the threads that need to be prioritized, use new Thread to create, and the rest of the threads are created using new Runnable. Because subclasses will have their own properties creation requires more overhead.
Control the maximum number of concurrency: Use Java's Executors class to control the maximum thread concurrency of the thread pool through Executors.newFixedThreadPool(nThreads) Increase timeout
for http requests

3. Layout optimization Some tags related to
performance optimization <viewStub/>, <merge/> and < include/> can be seen: http://hexen.blog.51cto.com/1110171/820197
TextView property optimization: TextView's android:ellipsize=”marquee” marquee effect consumes a lot of performance, the specific reason is still in the source code
For layout The actual effect of the layout can be viewed using hierarchyviewer.
For redundant views and incorrect labels in the layout, you can use android lint to view

. 4. Database optimization
mainly includes sql optimization, index building, transaction use, read and write table distinction
(1). sql optimization Yes
Refer to http://database.51cto.com/art/200904/118526.htm

(2). Create an index
Use the CREATE INDEX mycolumn_index ON mytable (myclumn) statement to create an index in the onCreate or onUpgrade function of the SQLiteOpenHelper subclass. The query performance improvement effect of large data volume is obvious

(3). Using transaction
Transaction can not only ensure that batch operations are completed or rolled back together, but also reduce the interaction between programs and tables when a large number of inserts, updates, and queries are used to improve performance.

Transaction example:

SQLiteDatabase db = dbHelper.getWritableDatabase();
db.beginTransaction();
try {
    // add to do
    db.setTransactionSuccessful();
} catch (Exception e) {
    Log.e(TAG, e.toString()) ;
} finally {
    db.endTransaction();
}
(4). Read-write table distinction
For query operations, use dbHelper.getReadableDatabase(); to read tables instead of write tables. Because sqlite is a table-level lock, write operations such as modifications and inserts have poor performance.

5. Algorithm optimization
This is a broad and profound topic, only the ones used in this application are introduced.
Using hashMap instead of arrayList reduces the time complexity by an order of magnitude


6. Delayed execution
For many time-consuming logics, it is not necessary to execute immediately, so we can delay the execution at this time.
Thread delayed execution ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
Message delayed sending handler.sendMessageDelayed(handler.obtainMessage(0), 1000);


Fourth, the performance tuning results of this program
1. ViewPager sliding left and right is obviously stuck
2. GridView scrolling up and down is obviously stuck
(1). Remove the android of TextView: ellipsize=”marquee”
(2). Modify the maximum number of threads in the image cache and increase the http timeout
(3). Modify the status of whether the app has been installed. The specific code is modified as follows:

List<PackageInfo> installedPackageList = getPackageManager().getInstalledPackages( PackageManager.GET_UNINSTALLED_PACKAGES);
List<App> installedAppList = function(installedAppList)
for (App app : appList) {
    for (App installedApp : installedAppList) {

    }
}
is modified to

for (App app : appList) {
    Pair<Integer, String> versionInfo = INSTALLED_APP_MAP.get(app.getPackageName());
    if (versionInfo != null) {

    } else {

    }
}
from getting List every time<PackageInfo> installedAppList = getPackageManager().getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES); is modified to get the app list only when there is an app install or uninstall broadcast, and Use hashMap instead of installedAppList to reduce query time.

Reduced the average execution time from 201ms to 1ms.


3. Other Activity returns ViewPager Activity is slow
Positioning : in the onStart function
Solution: use the delay strategy, the specific code is modified as follows:

@Override
public void onStart() {
    super.onStart();
    appUpdateListAdapter.notifyDataSetChanged();
}
to
public void onStart() {
    super.onStart();
    // delay send message
    handler.sendMessageDelayed(handler.obtainMessage(MessageConstants.WHAT_NOTIFY_DATA_CHANGED), 100);
}

private class MyHandler extends Handler {

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);

        switch (msg.what) {
            case MessageConstants.WHAT_NOTIFY_DATA_CHANGED:
                if (appUpdateListAdapter != null) {
                    appUpdateListAdapter.notifyDataSetChanged();
                }
                break;
        }
    }
}
4. 网络获取到展现速度较慢
定位:在HttpURLConnection.getInputStream()之后的处理
Solution: Use BufferedReader instead of BufferedInputStream to reduce the acquisition time from 100ms to 3ms. The specific code is modified as follows:

HttpURLConnection con = (HttpURLConnection)url.openConnection();
InputStream input = con.getInputStream();
while (input.read(buffer, 0, 1024) != -1) {

}
to
HttpURLConnection con = (HttpURLConnection)url.openConnection();
BufferedReader input = new BufferedReader(new InputStreamReader(con.getInputStream()));
String s;
while ((s = input. readLine()) != null) {

}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326527100&siteId=291194637