廣播
** 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)的通信方式,所以效率與安全性都更高。
用法:
- 創(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();
- 注冊(cè)廣播
LocalBroadcastManager.getInstance(context).registerReceiver(appReceiver, new IntentFilter(ACTION_SEND));
注:LocalBroadcastManager注冊(cè)廣播只能通過(guò)代碼注冊(cè)的方式,而不能通過(guò)xml中靜態(tài)配置,本地廣播并沒(mé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)先級(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)線程池:
-
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);
- ** newFixedThreadPool**定長(zhǎng)線程,固定線程池大小,定義如下:
new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
調(diào)用方法:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(nThreads);
fixedThreadPool.execute(runnable);
- ** newSingleThreadExecutor**只有一個(gè)線程的線程池,定義如下:
new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
調(diào)用方法:
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
newSingleThreadExecutor.execute(runnable);
- ** 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高;
對(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)。
循環(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);
}
- 采用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
- 同時(shí)需要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是整型時(shí),采用SparseArray,效率更高。避免了對(duì)key與value的自動(dòng)裝箱與解箱操作
Bitmap
- 使用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)存空間
- 使用SoftReference:當(dāng)內(nèi)存不足時(shí),虛擬機(jī)會(huì)自動(dòng)回收它;
- 使用Bitmap.recycle()釋放圖片,虛擬機(jī)gc時(shí)回收Bitmap;
- 根據(jù)手機(jī)尺寸大小,配置不同大小的圖片,保證使用盡可能小的圖片資源。
Object Pool
內(nèi)存對(duì)象,通過(guò)對(duì)象池技術(shù)來(lái)達(dá)到重復(fù)利用,減少對(duì)象重復(fù)創(chuàng)建。,從而減少內(nèi)存分配和回收。
- 復(fù)用系統(tǒng)自帶的資源,framework-res.apk中包含很多內(nèi)置資源,比如字符串/顏色/圖片/樣式/布局等??蓽p少APK大小、內(nèi)存開(kāi)銷。
- 緩存算法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/