Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> APP優化教程(一)

APP優化教程(一)

編輯:關於Android編程

本文是針對Android的App開發優化(一)

一、代碼優化

1. 廣播

應用程序內部廣播通信,優先采用LocalBroadcastManager,安全性更好,運行效率更高。

優勢:平時常說BroadcastReceiver,采用的是Binder通信方式,這是跨進程的通信方式,系統資源消耗固然更多。而廣播LocalBroadcastManager,采用的是Handler通信機制,Handler的實現是應用內的通信方式,所以效率與安全性都更高。

用法:

(1) 創建廣播接收者

//廣播類型
public static final String ACTION_SEND = "1";

//自定義廣播接收者
public class AppBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        //TODO
    }
}

//創建廣播接收者
AppBroadcastReceiver appReceiver = new AppBroadcastReceiver();

(2) 注冊廣播

LocalBroadcastManager.getInstance(context).registerReceiver(appReceiver, new IntentFilter(ACTION_SEND));

注:LocalBroadcastManager注冊廣播只能通過代碼注冊的方式,而不能通過xml中靜態配置,本地廣播並沒有走系統廣播的流程。

(3) 發送廣播

LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent(ACTION_SEND));

(4) 取消廣播

LocalBroadcastManager.getInstance(context).unregisterReceiver(appReceiver);

2. 線程池

線程創建優先采用線程池ThreadPoolExecutor,而不是new Thread(); 另外設置線程優先級為後台運行優先級,能有效減少Runnable創建的線程和和UI線程之間的資源競爭。

優勢: 通過new Thread()來創建線程是比較常用的方式,而使用線程池的方式有不少優勢如下

  • 線程可重復利用,節省線程的創建與銷毀開銷,性能有所提升;
  • 方便控制並發線程數,提高資源的利用率,減少過多的資源競爭;

用法:

//創建Runable對象
Runnable runnable = new Runnable() {
        @Override
        public void run() {
            android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
            //TODO
        }
    };
//創建線程池
ExecutorService threadPoolExecutor = new ThreadPoolExecutor(
    corePoolSize, maximumPoolSize,
    keepAliveTime, unit, workQueue);

//執行runnable
threadPoolExecutor.execute(runnable);

對於corePoolSize,一般往往可以設置為Runtime.getRuntime().availableProcessors(),代表當前系統活躍的CPU個數。

另外系統采用工廠模式,通過設置ThreadPoolExecutor的不同參數,提供四種默認線程池: (1) newCachedThreadPool 可緩存線程池,若線程空閒60s則回收,若無空閒線程可無限創建新線程,定義如下: new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());

調用方法:

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.execute(runnable);

(2) newFixedThreadPool 定長線程,固定線程池大小,定義如下: new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());

調用方法:

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(nThreads);
fixedThreadPool.execute(runnable);

(3) newSingleThreadExecutor 只有一個線程的線程池,定義如下: new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));

調用方法:

ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
newSingleThreadExecutor.execute(runnable);

(4) newScheduledThreadPool 可定時周期執行的線程池,定義如下: new ThreadPoolExecutor(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());

調用方法:

ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(corePoolSize);
scheduledThreadPool.schedule(runnable, delay, TimeUnit.SECONDS);

3. ArrayList Vs LinkedList

ArrayList基於動態數組的數據結構, 對於隨機訪問(get/set),ArrayList效率比LinkedList高; LinkedList基於鏈表的數據結構,對於新增和刪除(add/remove),LinedList效率比ArrayList高;

(1)對於list, 優先選擇ArrayList,除非少數需要大量的插入/刪除操作才使用LinkedList。因為當數據量非常大時get操作,LinkedList時間復雜度為o(n), 而ArrayList時間復雜度為o(1)。

(2)循環遍歷

LinkedList采用foreach方式, 效率最高。for循環方式效率大幅度降低。

List<Integer> list = new LinkedList<Integer>();
for (Integer j : list) {
    ... //TODO
}

ArrayList采用for循環+臨時變量保存size,效率最高。 foreach方式效率略微降低。

List<Integer> list = new ArrayList<Integer>();
int len = list.size();
for (int j = 0; j < len; j++) {
    list.get(j);
}

(3)采用new ArrayList()方式,初始大小為0,首次增加數組時,擴充大小到12,以後到數組需要增長時,會將大小增加50%,並將原來的成員全部復制到新的數組內。所以盡可能將ArrayList提前設置成目標大小,或者接近目標大小,以減少數組不斷創建與復制的過程,提高效率。

4. HashMap Vs SparseArray

(1)同時需要key和value,采用如下遍歷方法:

Map<String, String> map = new HashMap<String, String>();
for (Map.Entry<String, String> entry : map.entrySet()) {
        entry.getKey();
        entry.getValue();
}

(2)只需要獲取key,采用如下遍歷方法:

Map<String, String> map = new HashMap<String, String>();
for (String key : map.keySet()) {
    // key process
}

(3) 當HashMap的key是整型時,采用SparseArray,效率更高。避免了對key與value的自動裝箱與解箱操作。

5. Bitmap

  • 使用BitmapFactory.Options對圖片進行縮略讀取;減小內存使用量;
    • inSampleSize:縮放比例,在把圖片載入內存之前,先計算出一個合適的縮放比例,避免不必要的大圖載入
    • decode format:解碼格式,選擇ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,能減小內存空間
  • 使用SoftReference:當內存不足時,虛擬機會自動回收它;
  • 使用Bitmap.recycle()釋放圖片,虛擬機gc時回收Bitmap;
  • 根據手機尺寸大小,配置不同大小的圖片,保證使用盡可能小的圖片資源。

6. Object Pool

內存對象,通過對象池技術來達到重復利用,減少對象重復創建。,從而減少內存分配和回收。

  • 復用系統自帶的資源,framework-res.apk中包含很多內置資源,比如字符串/顏色/圖片/樣式/布局等。可減少APK大小、內存開銷。
  • 緩存算法LRU

7. Job Scheduler

使用Job Scheduler,應用需要做的事情就是判斷哪些任務是不緊急的,可以交給Job Scheduler來處理,Job Scheduler集中處理收到的任務,選擇合適的時間,合適的網絡,再一起進行執行。

8. Android避免使用Enum

Enum比靜態常量,至少需要多過於2倍以上的內存空間,應該在Android中避免使用枚舉。

9. onDraw()

由於onDraw方法調用比較頻繁,需避免對象創建操作,因為迅速增加內存,同樣引起頻繁的gc,甚至內存抖動。

10. 其他

  • 內部類引用導致Activity的洩漏,尤其是Handler
  • 監聽器即使注銷
  • 考慮使用Application Context而不是Activity Context
  • onLowMemory()與onTrimMemory()
  • 使用nano protobufs序列化數據
  • 使用IntentService
  • Adapter 利用convertView.getTag()與 ViewHolder
  • 窗口默認有一個不透明的背景,可以去掉的: getWindow().setBackground(null),或者修改xml
  • UI局部刷新
  • 在性能敏感的代碼,避免創建Java對象。比如onMeasure(), onLayout(), onDraw(), getView()等
  • 使用弱引用
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved