編輯:關於Android編程
安卓開發應用首先要講究良好的用戶體驗,如果一款軟件卡頓現象嚴重,不流暢,經常崩潰,那麼將給用戶帶來極不良好的體驗,從而損失用戶。
在實際開發和學習中,我總結了一下關於安卓性能的優化,供大家參考交流。
應用程序的性能問題體現在很多方面, 比如第一次啟動速度慢,或者進入某一界面速度慢;動畫執行過程不流暢,或者動畫執行卡頓時間長;ListView列表滑動過程中卡頓,不流暢;應用程序自定義的某特定界面執行速度慢;響應某一用戶事件時長時間無響應(ANR);操作數據庫時,執行大量數據的增刪改查操作,執行速度慢;文件讀寫頻繁,緩存文件過大導致卡頓;應用長時間運行後,隨機出現卡頓現象。
以上的問題的原因可能不只一個,並且很多情況下並不是應用本身的問題,也有可能是系統其他層次有問題,只不過體現在應用層。所以開發人員在處理性能問題時,需要做的第一件事情就是判斷是否是應用自身引起的性能問題,然後再對症下藥;但有些時候應用本身邏輯正常,但由於系統的硬件配置不足引起了異常,此時就要根據產品或項目需求,采取一些更加精准的方式優化性能,以彌補硬件配置的不足。
以下從幾個不同的角度總結一下應用程序性能優化的一些方法。
一、編程思想
應用層的性能優化通常可以從以下幾個方面考慮:
1. 了解編程語言的編譯原理,使用高效編碼方式從語法上提高程序性能;
2. 采用合理的數據結構和算法提高程序性能,這往往是決定程序性能的關鍵;
3. 重視界面布局優化;
4. 采用多線程、緩存數據、延遲加載、提前加載等手段,解決嚴重的性能瓶頸;
5. 合理配置虛擬機堆內存使用上限和使用率,減少垃圾回收頻率;
6. 合理使用native代碼;
7. 合理配置數據庫緩存類型和優化SQL語句加快讀取速度,使用事務加快寫入速度;
7. 使用工具分析性能問題,找出性能瓶頸;
當然肯定還有很多其他的性能優化方法,此處僅列出一些經常會用到的方法。
二、編程技巧
(一)Performance Tips (For Java)
Google官網上有一些關於應用程序性能提升的技巧,之前公司內也有很多總結提到過,在此簡單羅列一下,詳細內容可以從官網獲取。
http://developer.android.com/training/articles/perf-tips.html
需要說明的是,文章列出的優化技巧主要是一些微小的性能提升,決定程序整體性能的仍然取決於程序的業務邏輯設計、代碼的數據結構和算法。研發人員需要將這些優化技巧應用到平時的編碼過程中,積少成多,也會對性能有很大的影響。
寫出高效的代碼需要遵循兩條原則:
不執行不必要的操作;
不分配不必要的內存;
兩條原則分別針對CPU和內存,完成必要操作的前提下盡可能的節省CPU和內存資源,自然執行效率要高。單純這樣說聽起來很虛,畢竟沒有一個統一的標准判斷什麼是必要和不必要的,需要結合具體情況具體分析了。
1. 避免創建不必要的對象
創建太多的對象會造成性能低下,這誰都知道,可是為什麼呢?首先分配內存本身需要時間,其次虛擬機運行時堆內存使用量是有上限的,當使用量到達一定程度時會觸發垃圾回收,垃圾回收會使得線程甚至是整個進程暫停運行。可想而知,如果有對象頻繁的創建和銷毀,或者內存使用率很高,就會造成應用程序嚴重卡頓。
2.合理使用static成員
主要有三點需要掌握:
如果一個方法不需要操作運行時的動態變量和方法,那麼可以將方法設置為static的。
常量字段要聲明為“static final”,因為這樣常量會被存放在dex文件的靜態字段初始化器中被直接訪問,否則在運行時需要通過編譯時自動生成的一些函數來初始化。此規則只對基本類型和String類型有效。
不要將視圖控件聲明為static,因為View對象會引用Activity對象,當Activity退出時其對象本身無法被銷毀,會造成內存溢出。
**重點內容**3. 避免內部的Getters/Setters
面向對象設計中,字段訪問使用Getters/Setters通常是一個好的原則,但是在Android開發中限於硬件條件,除非字段需要被公開訪問,否則如果只是有限范圍內的內部訪問(例如包內訪問)則不建議使用Getters/Setters。在開啟JIT時,直接訪問的速度比間接訪問要快7倍。
4. 使用增強for循環
優先使用增強for循環通常情況下會獲得更高的效率;除了一種情況,即對ArrayList進行遍歷時,使用普通的for循環效率要更高。
5. 使用package代替private以便私有內部類高效訪問外部類成員
私有內部類的方法訪問外部類的私有成員變量和方法,在語法上是正確的,但是虛擬機在運行時並不是直接訪問的,而是在編譯時會在外部類中自動生成一些包級別的靜態方法,執行時內部類會調用這些靜態方法來訪問外部類的私有成員。這樣的話就多了一層方法調用,性能有所損耗。
一種解決這個問題的方法就是將外部類的私有成員改為包級別的,這樣內部類就可以直接訪問,當然前提是設計上可接受。
6.合理使用浮點類型
在Android設備中浮點型大概比整型數據處理速度慢兩倍,所以如果整型可以解決的問題就不要用浮點型。
另外,一些處理器有硬件乘法但是沒有除法,這種情況下除法和取模運算是用軟件實現的。為了提高效率,在寫運算式時可以考慮將一些除法操作直接改寫為乘法實現,例如將“x / 2”改寫為“x * 0.5”。
7.采用
優化布局層數。 采用
8.延時加載View. 采用ViewStub 避免一些不經常的視圖長期被引用,占用內存.
9.移除Activity默認背景,提升activity加載速度。
如果確信在Activity中使用不透明的背景,那麼可以移除Activity的默認背景。
在代碼中:getWindow().setBackgroundDrawable(null);
也可以在styles樣式文件中設置並在Manifest文件中配置
10.cursor 的使用。
要注意管理好cursor,不要每次打開關閉cursor.因為打開關閉Cursor非常耗時。
不再使用的cursor要記得關閉(一般在finally語句塊執行)。
有一種情況下,我們不能直接將Cursor關閉掉,這就是在CursorAdapter中應用的情況,但是注意,CursorAdapter在Acivity結束時並沒有自動的將Cursor關閉掉,因此,你需要在onDestroy函數中,手動關閉。
protected void onDestroy() {
if (mAdapter != null && mAdapter.getCurosr() != null) {
mAdapter.getCursor().close();
}
super.onDestroy();
}
11.廣播BroadCast動態注冊時,記得要在調用者生命周期結束時unregisterReceiver,防止內存洩漏。
12.針對ListView的性能優化
item盡可能的減少使用的控件和布局的層次;背景色與cacheColorHint設置相同顏色;ListView中item的布局至關重要,必須盡可能的減少使用的控件,布局。RelativeLayout是絕對的利器,通過它可以減少布局的層次。同時要盡可能的復用控件,這樣可以減少ListView的內存使用,減少滑動時GC次數。ListView的背景色與cacheColorHint設置相同顏色,可以提高滑動時的渲染性能。ListView中getView是性能是關鍵,這裡要盡可能的優化。getView方法中要重用view;getView方法中不能做復雜的邏輯計算,特別是數據庫操作,否則會嚴重影響滑動時的性能;ListView數據項較多時考慮分頁加載。
13.注意使用線程的同步機制(synchronized),防止多個線程同時訪問一個對象時發生異常。
14.合理使用StringBuffer,StringBuilder,String
在簡單的字符串拼接中,String的效率是最高的,例如String s = “hello” + “world”;
但大家這裡要注意的是,如果你的字符串是來自另外的String對象的話,速度就沒那麼快了,例如:
String str2 = “This is”;
String str3 = “ a ”;
String str4 = “ test”;
String str1 = str2 +str3 + str4;
這裡就要求使用StringBuilder了
在單線程中,StringBuilder的性能要比StringBuffer高。多線程為了線程安全需要采用StringBuffer,因為它是同步的。常規下一般用StringBuilder。
15. 盡量使用局部變量
調用方法時傳遞的參數以及在調用中創建的臨時變量都保存在棧(Stack)中,速度較快。其他變量,如靜態變量、實例變量等,都在堆(Heap)中創建,速度較慢。另外,依賴於具體的編譯器/JVM,局部變量還可能得到進一步優化。
16.I/O流操作記得及時關閉流對象。
17.使用IntentService代替Service
IntentService和Service都是一個服務,區別在於IntentService使用隊列的方式將請求的Intent加入隊列,然後開啟一個worker thread(線程)來處理隊列中的Intent(在onHandleIntent方法中),對於異步的startService請求,IntentService會處理完成一個之後再處理第二個,每一個請求都會在一個單獨的worker thread中處理,不會阻塞應用程序的主線程,如果有耗時的操作與其在Service裡面開啟新線程還不如使用IntentService來處理耗時操作。
18.使用Application Context代替Activity中的Context
不要讓生命周期長的對象引用activity context,即保證引用activity的對象要與activity本身生命周期是一樣的
對於生命周期長的對象,可以使用Application Context
不要把Context對象設置為靜態。
19.集合中的對象要及時清理
我們通常把一些對象的引用加入到了集合中,當我們不需要該對象時,並沒有把它的引用從集合中清理掉,這樣這個集合就會越來越大。如果這個集合是static的話,那情況就更嚴重了。
20.Bitmap的使用
較大的Bitmap注意壓縮後再使用,加載高清大圖可以考慮BitmapRegionDecoder的使用,
不再使用的Bitmap注意及時recycle().
21.巧妙的運用軟引用(SoftRefrence)
有些時候,我們使用Bitmap後沒有保留對它的引用,因此就無法調用Recycle函數。這時候巧妙的運用軟引用,可以使Bitmap在內存快不足時得到有效的釋放。有關Java引用機制的介紹可以看我的另一篇博客:http://blog.csdn.net/gs12software/article/details/51051813
22.盡量不要使用整張的大圖作為資源文件,盡量使用9path圖片
普通的資源圖優先放在mipmap目錄下(AndroidStudio環境),當然.9圖還不支持放在這個目錄,應該放在drawable
23.了解並使用庫函數
Java標准庫和Android Framework中包含了大量高效且健壯的庫函數,很多函數還采用了native實現,通常情況下比我們用Java實現同樣功能的代碼的效率要高很多。所以善於使用系統庫函數可以節省開發時間,並且也不容易出錯。
三、使用工具分析應用程序性能
(這部分內容較多,以後會在《Android開發性能優化總結(二)》中描述,待續。
現在物聯網搞的轟轟烈烈的,小米的手環等一系列產品,下面我們就來研究一下小米手環的記步功能 工具類package com.zsl.bluetoothdemo.ble;im
實現ListView過濾功能最方便的便是使用ArrayAdapter,裡面自帶的getFilter()方法能很方便的實現此功能但是在實際的開發中,ArrayAdapte
最近在項目開發中,由於項目的需求要實現一些列表的單選,多選,全選,批量輸入之類的功能,其實功能的實現倒不是很復雜,需求中也沒有涉及到復雜的動畫什麼之類,主要是解決列表數據
抽象工廠模式(Abstract Factory)抽象工廠模式是對象的創建模式,它是工廠方法模式的進一步延伸和拓展的結果。抽象工廠模式更加抽象化,更具一般性特點。我們知道,