App性能優(yōu)化

廣播

** LocalBroadcastManager**

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

優(yōu)勢(shì):平時(shí)常說(shuō)BroadcastReceiver,采用的是Binder通信方式,這是跨進(jìn)程的通信方式,系統(tǒng)資源消耗固然更多。而廣播LocalBroadcastManager,采用的是Handler通信機(jī)制,Handler的實(shí)現(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. 注冊(cè)廣播
LocalBroadcastManager.getInstance(context).registerReceiver(appReceiver, new IntentFilter(ACTION_SEND));

注:LocalBroadcastManager注冊(cè)廣播只能通過(guò)代碼注冊(cè)的方式,而不能通過(guò)xml中靜態(tài)配置,本地廣播并沒(mé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)先級(jí)為后臺(tái)運(yùn)行優(yōu)先級(jí),能有效減少Runnable創(chuàng)建的線程和和UI線程之間的資源競(jìng)爭(zhēng)。

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

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

用法:

//創(chuàng)建Runable對(duì)象
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);

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

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

  1. ThreadPoolExecutor
    可緩存線程池,若線程空閑60s則回收,若無(wú)空閑線程可無(wú)限創(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**定長(zhǎng)線程,固定線程池大小,定義如下:
    new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
    調(diào)用方法:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(nThreads);
fixedThreadPool.execute(runnable);
  1. ** newSingleThreadExecutor**只有一個(gè)線程的線程池,定義如下:
    new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
    調(diào)用方法:
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
newSingleThreadExecutor.execute(runnable);
  1. ** newScheduledThreadPool**可定時(shí)周期執(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基于動(dòng)態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu), 對(duì)于隨機(jī)訪問(wèn)(get/set),ArrayList效率比LinkedList高; LinkedList基于鏈表的數(shù)據(jù)結(jié)構(gòu),對(duì)于新增和刪除(add/remove),LinedList效率比ArrayList高;

  1. 對(duì)于list, 優(yōu)先選擇ArrayList,除非少數(shù)需要大量的插入/刪除操作才使用LinkedList。因?yàn)楫?dāng)數(shù)據(jù)量非常大時(shí)get操作,LinkedList時(shí)間復(fù)雜度為o(n), 而ArrayList時(shí)間復(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)+臨時(shí)變量保存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ù)組時(shí),擴(kuò)充大小到12,以后到數(shù)組需要增長(zhǎng)時(shí),會(huì)將大小增加50%,并將原來(lái)的成員全部復(fù)制到新的數(shù)組內(nèi)。所以盡可能將ArrayList提前設(shè)置成目標(biāo)大小,或者接近目標(biāo)大小,以減少數(shù)組不斷創(chuàng)建與復(fù)制的過(guò)程,提高效率。

HashMap Vs SparseArray

  1. 同時(shí)需要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是整型時(shí),采用SparseArray,效率更高。避免了對(duì)key與value的自動(dòng)裝箱與解箱操作

Bitmap

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

Object Pool

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

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

Job Scheduler

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

Android 避免使用Enum

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

onDraw()

由于onDraw方法調(diào)用比較頻繁,需避免對(duì)象創(chuàng)建操作,因?yàn)檠杆僭黾觾?nèi)存,同樣引起頻繁的gc,甚至內(nèi)存抖動(dòng)。

其他

  • 內(nèi)部類引用導(dǎo)致Activity的泄漏,尤其是Handler
  • 監(jiān)聽(tīng)器即使注銷
  • 考慮使用Application Context而不是Activity Context
  • onLowMemory()與onTrimMemory()
  • 使用nano protobufs序列化數(shù)據(jù)
  • 使用IntentService
  • Adapter 利用convertView.getTag()與 ViewHolder
  • 窗口默認(rèn)有一個(gè)不透明的背景,可以去掉的: getWindow().setBackground(null),或者修改xml
  • UI局部刷新
  • 在性能敏感的代碼,避免創(chuàng)建Java對(duì)象。比如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)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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

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