App性能優(yōu)化

廣播

** LocalBroadcastManager**

應(yīng)用程序內(nèi)部廣播通信,優(yōu)先采用LocalBroadcastManager,安全性更好,運行效率更高。

優(yōu)勢:平時常說BroadcastReceiver,采用的是Binder通信方式,這是跨進程的通信方式,系統(tǒng)資源消耗固然更多。而廣播LocalBroadcastManager,采用的是Handler通信機制,Handler的實現(xiàn)是應(yīng)用內(nèi)的通信方式,所以效率與安全性都更高。

用法:

  1. 創(chuàng)建廣播接收者
//廣播類型
public static final String ACTION_SEND = "1";
//自定義廣播接收者
public class AppBroadcastReceiver extends BroadcastReceiver {
  @Override
  public void onReceive(Context context, Intent intent) {
      //TODO
  }
}
//創(chuàng)建廣播接收者
AppBroadcastReceiver appReceiver = new AppBroadcastReceiver();
  1. 注冊廣播
LocalBroadcastManager.getInstance(context).registerReceiver(appReceiver, new IntentFilter(ACTION_SEND));

注:LocalBroadcastManager注冊廣播只能通過代碼注冊的方式,而不能通過xml中靜態(tài)配置,本地廣播并沒有走系統(tǒng)廣播的流程。

  1. 發(fā)送廣播
LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent(ACTION_SEND));
  1. 取消廣播
LocalBroadcastManager.getInstance(context).unregisterReceiver(appReceiver);

線程池

線程創(chuàng)建優(yōu)先采用線程池ThreadPoolExecutor,而不是new Thread(); 另外設(shè)置線程優(yōu)先級為后臺運行優(yōu)先級,能有效減少Runnable創(chuàng)建的線程和和UI線程之間的資源競爭。

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

  • 線程可重復(fù)利用,節(jié)省線程的創(chuàng)建與銷毀開銷,性能有所提升;
  • 方便控制并發(fā)線程數(shù),提高資源的利用率,減少過多的資源競爭;

用法:

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

對于corePoolSize,一般往往可以設(shè)置為Runtime.getRuntime().availableProcessors(),代表當(dāng)前系統(tǒng)活躍的CPU個數(shù)。

另外系統(tǒng)采用工廠模式,通過設(shè)置ThreadPoolExecutor的不同參數(shù),提供四種默認線程池:

  1. ThreadPoolExecutor
    可緩存線程池,若線程空閑60s則回收,若無空閑線程可無限創(chuàng)建新線程,定義如下:
    new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
    調(diào)用方法:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.execute(runnable);
  1. ** newFixedThreadPool**定長線程,固定線程池大小,定義如下:
    new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
    調(diào)用方法:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(nThreads);
fixedThreadPool.execute(runnable);
  1. ** newSingleThreadExecutor**只有一個線程的線程池,定義如下:
    new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
    調(diào)用方法:
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
newSingleThreadExecutor.execute(runnable);
  1. ** newScheduledThreadPool**可定時周期執(zhí)行的線程池,定義如下:
    new ThreadPoolExecutor(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
    調(diào)用方法:
ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(corePoolSize);
scheduledThreadPool.schedule(runnable, delay, TimeUnit.SECONDS);

ArrayList Vs LinkedList

ArrayList基于動態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu), 對于隨機訪問(get/set),ArrayList效率比LinkedList高; LinkedList基于鏈表的數(shù)據(jù)結(jié)構(gòu),對于新增和刪除(add/remove),LinedList效率比ArrayList高;

  1. 對于list, 優(yōu)先選擇ArrayList,除非少數(shù)需要大量的插入/刪除操作才使用LinkedList。因為當(dāng)數(shù)據(jù)量非常大時get操作,LinkedList時間復(fù)雜度為o(n), 而ArrayList時間復(fù)雜度為o(1)。

  2. 循環(huán)遍歷
    LinkedList采用foreach方式, 效率最高。for循環(huán)方式效率大幅度降低。

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

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

List<Integer> list = new ArrayList<Integer>();
int len = list.size();
for (int j = 0; j < len; j++) {
  list.get(j);
}
  1. 采用new ArrayList()方式,初始大小為0,首次增加數(shù)組時,擴充大小到12,以后到數(shù)組需要增長時,會將大小增加50%,并將原來的成員全部復(fù)制到新的數(shù)組內(nèi)。所以盡可能將ArrayList提前設(shè)置成目標(biāo)大小,或者接近目標(biāo)大小,以減少數(shù)組不斷創(chuàng)建與復(fù)制的過程,提高效率。

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();
}
  1. 只需要獲取key,采用如下遍歷方法:
Map<String, String> map = new HashMap<String, String>();
for (String key : map.keySet()) {
  // key process
}
  1. 當(dāng)HashMap的key是整型時,采用SparseArray,效率更高。避免了對key與value的自動裝箱與解箱操作

Bitmap

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

Object Pool

內(nèi)存對象,通過對象池技術(shù)來達到重復(fù)利用,減少對象重復(fù)創(chuàng)建。,從而減少內(nèi)存分配和回收。

  1. 復(fù)用系統(tǒng)自帶的資源,framework-res.apk中包含很多內(nèi)置資源,比如字符串/顏色/圖片/樣式/布局等??蓽p少APK大小、內(nèi)存開銷。
  2. 緩存算法LRU

Job Scheduler

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

Android 避免使用Enum

Enum比靜態(tài)常量,至少需要多過于2倍以上的內(nèi)存空間,應(yīng)該在Android中避免使用枚舉。

onDraw()

由于onDraw方法調(diào)用比較頻繁,需避免對象創(chuàng)建操作,因為迅速增加內(nèi)存,同樣引起頻繁的gc,甚至內(nèi)存抖動。

其他

  • 內(nèi)部類引用導(dǎo)致Activity的泄漏,尤其是Handler
  • 監(jiān)聽器即使注銷
  • 考慮使用Application Context而不是Activity Context
  • onLowMemory()與onTrimMemory()
  • 使用nano protobufs序列化數(shù)據(jù)
  • 使用IntentService
  • Adapter 利用convertView.getTag()與 ViewHolder
  • 窗口默認有一個不透明的背景,可以去掉的: getWindow().setBackground(null),或者修改xml
  • UI局部刷新
  • 在性能敏感的代碼,避免創(chuàng)建Java對象。比如onMeasure(), onLayout(), onDraw(), getView()等
  • 使用弱引用

相關(guān)資料

http://developer.android.com/training/displaying-bitmaps/index.html
http://www.trinea.cn/android/hashmap-loop-performance/
http://hukai.me/android-performance-oom/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,896評論 18 399
  • 當(dāng)出現(xiàn)App啟動慢、界面跳轉(zhuǎn)慢、事件相應(yīng)慢、滑動和動畫卡頓、展現(xiàn)內(nèi)容慢等問題的時候意味著App性能出現(xiàn)問題,這個時...
    Kurtis閱讀 385評論 0 0
  • 一般我們寫的app操作的數(shù)據(jù)多的時侯或者平時使用的時候都會經(jīng)常出現(xiàn)卡頓、閃退、ANR停止運行等各種問題。這樣會導(dǎo)致...
    踏雪羽翼閱讀 790評論 0 1
  • 父母給予你善良的樣貌 你跟隨命運,成為一個善良的人 即使你是披著羊皮的狼 在眾人眼里你仍是善良之輩 父母給予你老實...
    鹿原先生和蓬蒿閱讀 327評論 6 9
  • Art藝生活閱讀 853評論 0 0

友情鏈接更多精彩內(nèi)容