編寫高效代碼的兩個基本原則:
不要做冗余的工作。
盡量避免次數(shù)過多的內(nèi)存分配操作
數(shù)據(jù)結構的選擇
正確的選擇合適的數(shù)據(jù)結構很重要。
對Java中常見的數(shù)據(jù)結構--例如ArrayList和LinkedList、HashMap、HashSet等
SparseArray代替HashMap
Android原生的數(shù)據(jù)結構
SparseArray家族目前有以下四類:
SparseBooleanArray用于替代HashMap<Integer,Boolean>
SparseIntArray用于替代HashMap<Integer,Integer>
SparseLongArray用于替代HashMap<Integer,Long>
SparseArray<String>用于替代HashMap<Integer,String>
注意
SparseArray不是線程安全的
由于要進行二分查找,因此,SparseArray會對插入的數(shù)據(jù)按照Key值大小順序插入
SparseArray對刪除操作做了優(yōu)化,它并不會立即刪除這個元素,而是通過設置標識位(DELETED)的方式,后面嘗試重用。
防止內(nèi)存泄漏
Handler和內(nèi)部類的正確用法
handler消息處理機制
內(nèi)存泄漏原因
1.Handler是和Looper以及MessageQueeue一起工作。
在Android啟動后,系統(tǒng)會默認創(chuàng)建一個為主線程服務的Looper對象,該Looper對象用于處理主線程的message對象。在主線程中創(chuàng)建Handler對象時,它會立即關聯(lián)主線程Looper對象的MessageQueue這時發(fā)送到MessageQueue中的message對象都會持有Handler對象的引用,這樣在Looper處理消息時才能回調HandlerMessage方法。因此message沒有處理完成,那么Handler對象也就不會被垃圾回收。
2.Java語言中非靜態(tài)內(nèi)部類會持有外部類的一個隱式引用這樣就可能導致外部類無法回收。最終由于MessageQueue中的Message還沒有處理完成,就會持有Handler對象的引用,而非靜態(tài)的Handler對象外部類的引用,這個外部類無法被回收。
解決
1.子線程中使用Handler,這個時候開發(fā)者襲擊創(chuàng)建一個looper對象,這個Looper對象的生命周期同一般的Java對象,因此這種用法沒問題
2.將handler聲明為靜態(tài)內(nèi)部類,靜態(tài)內(nèi)部類不會持有外部類的引用,因此,不會引起內(nèi)存泄漏。
正確使用context
Context的種類
Application:Android應用中默認單例類,在activity或者service中通過getApplication()獲取到這個單例,通過context.getApplicationContext()可以獲取到應用全局唯一的Context實例。
activity/service這兩個類ContextWrapper的子類,在這兩個類中可以通過getBaseContxt()獲取到它們的Context實例,不同的activity或者service實例,它們的context都是獨立的,不會復用。、
BroadcastReceiver本身不是context的子類,但在回調函數(shù)onReceive中有android框架傳入一個context實例,它不能調用registerReceiver()以及bindService();
ContentProvider不是context子類,創(chuàng)建時系統(tǒng)會傳一個context實例,在ContentProvider中可以通過getContext()函數(shù)獲取,ContentProvider和調用者處于相同的進程中,那么getContext()返回的是應用全局唯一的context。如果其他進程調用ContentProvider,那么ContentProvider將持有自身所在進程的context實例。
錯誤使用context導致的內(nèi)存泄漏
典型的例子是單例模式使用
在應用退出之前,由于單例一直存在,會導致activity或service被引用,從而不會被垃圾回收,activity或者service中關聯(lián)的其他view或者數(shù)據(jù)結構對象也不會被釋放,從而導致內(nèi)存泄漏。
正確的是使用ApplicationContext,因為它是唯一的。
其他代碼微優(yōu)化
1-避免創(chuàng)建非必要對象
特別是在循環(huán)中重復創(chuàng)建相同對象,最好重用對象。
2-對常量使用static final
final類型的常量會進入靜態(tài)dex文件的域初始化部分,這是對基本數(shù)據(jù)類型和string類型常量的調用不會涉及類的初始化,而是直接調用字面量
3-避免內(nèi)部的Getters/Setters
Getters/Setters的作用主要是對外屏蔽具體的變量定義,從而達到更好的封裝性。
但是如果在類內(nèi)部還使用Getters/Setters函數(shù)訪問變量的話,會降低訪問的速度
4-代碼的重構
Java的四種引用方式
1-強引用
Java里對象默認的引用類型,如果一個對象具有強引用,那么垃圾回收器是不會對它進行回收操作,當內(nèi)存空間不足時,Java虛擬機將會拋出OutOfMemoryError,這是應用將會終止運行。
顯示地將引用賦值為null,JVM在合適的時間就會回收該對象
2-軟引用SoftReference
一個對象如果只有軟引用,那么當內(nèi)存空間充足時,垃圾回收器不會對它進行回收操作,只有當內(nèi)存空間不足時,這個對象才會被回收。軟引用可以用來實現(xiàn)內(nèi)存敏感的高速緩存。
MyObject aRef = new MyObject();
SoftReference aSoftRef=new SoftReference(aRef);
對于這個MyObject對象,有兩個引用路徑,一個是來自SoftReference對象的軟引用,一個來自變量aReference的強引用,所以這個MyObject對象是強可及對象。
在回收這些對象之前,我們可以通過:
MyObject anotherRef=(MyObject)aSoftRef.get();
重新獲得對該實例的強引用。而回收之后,調用get()方法就只能得到null了。
3-弱引用WeakReference
弱引用是比軟引用更弱的一種引用類型,只有弱引用指向的對象的生命周期更短,當垃圾回收器掃描到只具有弱引用時,不論當前的內(nèi)存是否不足,都會對弱引用對象進行回收。
只要JVM進行垃圾回收,被弱引用關聯(lián)的對象必定會被回收掉。不過要注意的是,這里所說的被弱引用關聯(lián)的對象是指只有弱引用與之關聯(lián),如果存在強引用同時與之關聯(lián),則進行垃圾回收時也不會回收該對象(軟引用也是如此)。
虛引用PhantomReference
虛引用并不會對所指向的對象生命周期產(chǎn)生任何影響,也就是對象還是會按照它原來的方式被垃圾回收器回收,虛引用只是一個標記作用,主要是用來跟蹤對象被垃圾回收的活動,虛引用必須和引用隊列配合使用