Android設備做爲一種移動設備,不論是內存仍是CPU的性能都受到了必定的限制,沒法作到像PC設備那樣具備超大的內存和高性能的CPU,這也意味着Android程序不可能無限制地使用內存和CPU資源,過多地使用內存會致使程序內存溢出,即OOM。而過多地使用CPU資源,通常指作大量的耗時任務,會致使手機變得卡頓甚至出現沒法響應的狀況,即ANR。緩存
Android的性能優化方法性能優化
一、佈局優化bash
佈局優化的思想很簡單,就是儘可能減小布局文件的層級,佈局中的層級少了,這就意味着Android繪製時的工做量少了,那麼程序的性能天然就高了。數據結構
那麼如何進行佈局優化呢?有如下兩點:併發
• 首先刪除佈局中無用的看控件和層級,其次有選擇地使用性能較低的ViewGroup,好比RelativeLayout。
• 能夠採用標籤、標籤、ViewStub。標籤主要用於佈局重用,標籤通常配合標籤使用,它能夠下降減小布局的層級,而ViewStub則提供了按需加載的功能。異步
二、繪製優化ide
繪製優化是指View的onDraw方法要避免執行大量的操做,主要體如今兩個方面:工具
• onDraw中不要建立新的局部對象,這是由於onDraw方法可能會被頻繁調用,這樣就會在一瞬間產生大量的臨時對象,這不只佔用了過多的內存並且還會致使系統會更頻繁gc,下降程序的執行效率。佈局
• onDraw方法中不要作耗時的任務,也不能執行成千上萬次的循環操做,儘管每次循環都很輕量級,可是大量的循環仍然十分搶佔CPU的時間片,這會形成View的繪製過程很不流暢。性能
三、內存優化
內存泄露在開發過程當中是一個須要重視的問題,內存優化分爲兩個方面,一方面是在開發過程當中避免寫出有內存泄露的代碼,另外一方面是經過一些分析工具好比MAT來找出潛在的內存泄露繼而解決。
場景1:靜態變量致使內存泄露
好比下面這段代碼:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private static Context sContext;
private static View sView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sContext = this;
sView = new View(this);
}
}複製代碼
MainActivity沒法正常銷燬,由於靜態變量sContext引用了它。一樣,sView是一個靜態變量,他內部持有了當前Activity,因此Activity仍然沒法釋放。
場景2:單例模式致使內存泄露
靜態變量致使的內存泄露都太過明顯了,但單例模式所帶來的內存泄露是咱們容易忽視的。好比下面這段代碼:
public class TestManager {
private List mOnDataArrivedListeners = new ArrayList();
private static class SingletonHolder {
public static final TestManager INSTANCE = new TestManager();
}
private TestManager() {
}
public static TestManager getInstance() {
return SingletonHolder.INSTANCE;
}
public synchronized void registerListener(OnDataArrivedListener listener) {
if (!mOnDataArrivedListeners.contains(listener)) {
mOnDataArrivedListeners.add(listener);
}
}
public synchronized void unregisterListener(OnDataArrivedListener listener) {
mOnDataArrivedListeners.remove(listener);
}
public interface OnDataArrivedListener {
public void onDataArrived(Object data);
}
}
複製代碼
首先提供一個單例模式的TestManager,TestManager能夠接收外部的註冊並將外部的監聽器存儲起來。而後用Activity實現OnDataArrivedListener接口並向TestManager註冊監聽,可是若是缺乏解註冊的操做,會引發內存泄露。好比下面這段代碼:
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TestManager.getInstance().registerListener(this);
}
複製代碼
Activity的對象被單例模式的TestManager所持有,而單例模式的特色是其生命週期和Application保持一致,所以Activity對象沒法被及時釋放。
場景3:屬性動畫致使的內存泄露
從Android3.0開始,Google提供了屬性動畫,屬性動畫中有這麼一類無限循環的動畫,若是在Activity中播放此類動畫且沒有在onDestroy中中止動畫,那麼動畫就會一直播放下去,儘管已經沒法在界面上看到動畫效果,但這個時候Activity的View會被動畫持有,而View又持有了Activity,最終Activity沒法釋放。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ObjectAnimator animator = ObjectAnimator.ofFloat(mButton, "rotation", 0, 360).setDuration(2000);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.start(); //animator.cancel(); }
}複製代碼
四、響應速度優化和ANR日誌分析
響應速度優化的核心思想是避免在主線程中作耗時操做,可是有時候的確有不少耗時操做,怎麼辦呢?能夠將這些耗時操做放在線程中去執行,即採用異步的方式執行耗時操做。響應速度過慢更多地體如今Activity的啓動速度上面,若是在主線程中作太多的事情,會致使Activity啓動出現黑屏現象,甚至出現ANR。Android規定,Activity若是5秒鐘以內沒法響應屏幕觸摸事件或者鍵盤輸入事件就會出現ANR,而BroadcastReceiver若是10秒以內還未執行完操做也會出現ANR,那麼在實際開發過程當中遇到ANR,怎麼定位問題呢?其實當一個進程發生ANR了之後,系統會在/data/anr/目錄下建立一個文件traces.txt,經過分析這個文件就能定位出ANR的緣由。好比下面代碼在Activity的onCreate中休眠30s,程序運行持續點擊屏幕,應用必定會出現ANR:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SystemClock.sleep(30 * 1000);
}複製代碼
五、ListView和Bitmap優化
ListView優化三個方面:
• 採用ViewHolder並避免在getView中執行耗時操做
• 根據列表的滑動狀態來控制任務的執行頻率,好比當列表快速滑動時顯然是不太適合開啓大量異步任務的。
• 嘗試開啓硬件加速來使ListView的滑動更加流暢。
Bitmap優化,主要是經過BitmapFactory.Options來根據須要對圖片進行採樣,採樣過程當中主要用到了BitmapFactory.Option的inSampleSize參數。
六、線程優化
線程優化的思想是採用線程池,避免在程序中存在大量的Thread。線程池能夠重用內部的線程,從而避免了現場的建立和銷燬所帶來的性能開銷,同時線程池還能有效地控制線程池的最大併發數,避免大量的線程因互相搶佔系統資源從而致使阻塞現象發生。
七、其餘性能優化建議
還有一些其餘性能優化的小建議,經過它們能夠在必定程度上提升性能:
• 避免建立過多的對象
• 不要過多使用枚舉,枚舉佔用的內存空間要比整型大
• 常量請用static final來修飾
• 使用一些Android特有的數據結構,好比SpareArray和Pair等,它們都具備更好的性能
• 適當使用軟引用和弱引用
• 採用內存緩存和磁盤緩存
• 儘可能採用靜態內部類,這樣能夠避免在的因爲內部類而致使的內存泄露
內存泄露分析之MAT工具
MAT的全稱是Eclipse Memory Analyzer,他是一款強大的內存泄露分析工具。MAT提供了不少功能,可是最經常使用的只有Histogram和Dominator Tree,經過Histogram能夠直觀看出內存中不一樣類型的buffer的數量和佔用的內存大小,而Dominator Tree則把內存中的對象按照從大到小的順序進行排序,而且能夠分析對象之間的引用關係,內存泄露分析就是經過Dominator Tree來完成。在Dominator Tree中內存泄露的緣由通常不會直接顯示出來,這個時候須要按照從大到小的順序去排查一遍。
提升程序的可維護性
主要是提升代碼的可維護性和可擴展性,而程序的可維護性本質上也包含可擴展性。
• 命名要規範,要能正確地傳達出變量或者方法的含義,少用縮寫,關於變量的前綴能夠參考Android源碼的命名方式,好比私有方式以m開頭,靜態成員以s開頭,常量則所有用大寫字母表示,等等。• 代碼的排版上須要留出合理的空白區分不一樣的代碼塊,其中同類變量的聲明要放在一組,兩類變量之間要留出一行空白做爲區分。• 僅爲很是關鍵的代碼添加註釋,其餘地方不寫註釋,這就對變量和方法的命名風格提出了很高的要求。• 代碼的層次性指代碼要有分層的概念,對於一段業務邏輯,不要試圖在一個方法或者一個類中去所有實現,它能夠分紅幾個子邏輯,而後每一個子邏輯作本身的事情。單一職責是和層次性相關聯,代碼分紅之後,每一層僅僅關注少許的邏輯,這樣就作到了單一職責。