廣播
** LocalBroadcastManager**
應(yīng)用程序內(nèi)部廣播通信,優(yōu)先采用LocalBroadcastManager窖张,安全性更好隅熙,運行效率更高。
優(yōu)勢:平時常說BroadcastReceiver森逮,采用的是Binder通信方式,這是跨進程的通信方式磁携,系統(tǒng)資源消耗固然更多褒侧。而廣播LocalBroadcastManager,采用的是Handler通信機制谊迄,Handler的實現(xiàn)是應(yīng)用內(nèi)的通信方式闷供,所以效率與安全性都更高。
用法:
- 創(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();
- 注冊廣播
LocalBroadcastManager.getInstance(context).registerReceiver(appReceiver, new IntentFilter(ACTION_SEND));
注:LocalBroadcastManager注冊廣播只能通過代碼注冊的方式统诺,而不能通過xml中靜態(tài)配置歪脏,本地廣播并沒有走系統(tǒng)廣播的流程。
- 發(fā)送廣播
LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent(ACTION_SEND));
- 取消廣播
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ù),提供四種默認線程池:
-
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);
- ** newFixedThreadPool**定長線程乎折,固定線程池大小,定義如下:
new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
調(diào)用方法:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(nThreads);
fixedThreadPool.execute(runnable);
- ** newSingleThreadExecutor**只有一個線程的線程池侵歇,定義如下:
new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
調(diào)用方法:
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
newSingleThreadExecutor.execute(runnable);
- ** 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高健提;
對于list, 優(yōu)先選擇ArrayList,除非少數(shù)需要大量的插入/刪除操作才使用LinkedList伟叛。因為當(dāng)數(shù)據(jù)量非常大時get操作私痹,LinkedList時間復(fù)雜度為o(n), 而ArrayList時間復(fù)雜度為o(1)。
循環(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);
}
- 采用new ArrayList()方式鞭衩,初始大小為0学搜,首次增加數(shù)組時娃善,擴充大小到12,以后到數(shù)組需要增長時瑞佩,會將大小增加50%会放,并將原來的成員全部復(fù)制到新的數(shù)組內(nèi)。所以盡可能將ArrayList提前設(shè)置成目標(biāo)大小钉凌,或者接近目標(biāo)大小咧最,以減少數(shù)組不斷創(chuàng)建與復(fù)制的過程,提高效率御雕。
HashMap Vs SparseArray
- 同時需要key和value矢沿,采用如下遍歷方法:
Map<String, String> map = new HashMap<String, String>();
for (Map.Entry<String, String> entry : map.entrySet()) {
entry.getKey();
entry.getValue();
}
- 只需要獲取key,采用如下遍歷方法:
Map<String, String> map = new HashMap<String, String>();
for (String key : map.keySet()) {
// key process
}
- 當(dāng)HashMap的key是整型時酸纲,采用SparseArray捣鲸,效率更高。避免了對key與value的自動裝箱與解箱操作
Bitmap
- 使用BitmapFactory.Options對圖片進行縮略讀让銎隆栽惶;減小內(nèi)存使用量;
- inSampleSize:縮放比例疾嗅,在把圖片載入內(nèi)存之前外厂,先計算出一個合適的縮放比例,避免不必要的大圖載入
- decode format:解碼格式代承,選擇ARGB_8888/RBG_565/ARGB_4444/ALPHA_8汁蝶,能減小內(nèi)存空間
- 使用SoftReference:當(dāng)內(nèi)存不足時,虛擬機會自動回收它论悴;
- 使用Bitmap.recycle()釋放圖片掖棉,虛擬機gc時回收Bitmap;
- 根據(jù)手機尺寸大小,配置不同大小的圖片膀估,保證使用盡可能小的圖片資源幔亥。
Object Pool
內(nèi)存對象,通過對象池技術(shù)來達到重復(fù)利用察纯,減少對象重復(fù)創(chuàng)建帕棉。,從而減少內(nèi)存分配和回收捐寥。
- 復(fù)用系統(tǒng)自帶的資源笤昨,framework-res.apk中包含很多內(nèi)置資源,比如字符串/顏色/圖片/樣式/布局等握恳÷髦希可減少APK大小、內(nèi)存開銷乡洼。
- 緩存算法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/