標籤:sensor 提高 nali 退出 owb 虛擬 font bit 技術分享
布局最佳化
Android效能最佳化之如何避免Overdraw(可參考)
(1)避免Overdraw
Overdraw,過度繪製會浪費很多的cpu,Gpu資源,例如系統預設會繪製Activity的背景,如果在給布局重新繪製了重疊的背景,那麼預設的Activity的背景就屬於無效的過度繪製。
過度繪製(Overdraw)也是很浪費CPU/GPU資源的,系統也提供了偵查工具Debug GPU Overdraw來查看介面overdraw的情況。該工具會使用不同的顏色繪製螢幕,來指示overdraw發生在哪裡以及程度如何,其中:
沒有顏色: 意味著沒有overdraw。像素只畫了一次。
藍色: 意味著overdraw 1倍。像素繪製了兩次。大片的藍色還是可以接受的(若整個視窗是藍色的,可以擺脫一層)。
綠色: 意味著overdraw 2倍。像素繪製了三次。中等大小的綠色地區是可以接受的但你應該嘗試最佳化、減少它們。
淺紅: 意味著overdraw 3倍。像素繪製了四次,小範圍可以接受。
暗紅: 意味著overdraw 4倍。像素繪製了五次或者更多。這是錯誤的,要修複它們。
(2)最佳化布局層次
在Android中,系統對View的進行測量、布局和繪製時,都是通過對View樹的遍曆來進行操作的。如果一個View的高度太高,就會影響測量、布局和繪製的速度,因此最佳化布局的第一個方法就是降低View樹的高度,Google在器API文檔中也建議View樹的高度不超過10層。
避免嵌套過多無用布局:
①使用<include>標籤重用layout
在一個應用程式中介面中,為了風格上的統一,很多介面都會存在一些共通的UI,對於這些共通的UI,如果在每個介面中都來複製一段這樣的代碼,不僅不利於後期的維護,更增加了程式的冗餘性。因此可以使用<include>標籤來定義這樣一個共通的UI。
我們先來定義一個簡單的共通的UI:
代碼中,將 android:layout_width="0dp" 和android:layout_height="0dp"都設定為0,這樣迫使開發人員在使用時對寬高進行賦值,否則無法看見這個介面。
<?xml version="1.0" encoding="utf-8"?></span><span style="font-family:微軟雅黑;"><TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="0dp" android:layout_height="0dp" android:textSize="30dp" android:gravity="center" android:text="this is a common ui" />
<include layout="@layout/common_ui" android:layout_alignParentBottom="true" android:layout_width="match_parent" android:layout_height="wrap_content"/>
如果需要在<include>標籤中覆蓋類似原布局中的android:layout_xxx的屬性,就必須在標籤中同時指定android:layout_width和android:layout_height屬性。
②使用實現view的消極式載入
<ViewStub>是一個非常輕量級的組件,它不僅不可見,而且大小為0。
首先建立一個布局,這個布局在初始化載入時不需要顯示,只在某些情況下才顯示出來,例如查看使用者資訊的時,只有點擊了某個按鈕是,使用者詳細資料才顯示出來。我們寫一個簡單的布局:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="not often use layout" android:textSize="30sp"/></LinearLayout>
接下來與使用<include>標籤類似,在主布局中的<ViewStub>中的layout屬性來引用上面的布局。
<ViewStub android:id="@+id/not_often_use" android:layout_alignParentBottom="true" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout="@layout/not_often_use"/>
如何重新載入顯示的布局呢?
首先,通過普通的findViewById()方法找到<ViewStub>組件,這點與一般的組件基本相同:
mViewStub = (ViewStub)findViewById(R.id.not_often_use);
接下來,有兩種方式重新顯示這個View.
(1)VISIBLE
通過調用ViewStub的setVisibility()方法來顯示這個View,代碼如下所示:
mViewStub.setVisibility(View.VISIBLE);
( 2 ) inflate
通過調用ViewStub的inflate()方法來顯示這個View,代碼如下:
View inflateView = mViewStub.inflate();
這兩種方式都可以讓ViewStub重新展開,顯示引用的布局,而唯一的區別就是inflate()方法可以返回引用的布局,從而可以在通過View.findViewById()方法來找到對應的控制項,代碼如下:
View inflateView = mViewStub.inflate();
TextView textview = (TextView) inflateView.findViewById(R.id.Tv);
textView.setText(“Hello“);
ViewStub和View.GONE有啥區別?
它們的共同點是初始時都不會顯示,但是前者只會在顯示時才去渲染整個布局,而後者在初始化布局樹的時候就已經添加到布局樹上了,相比之下前者的布局具有更高的效率。
③Hierarchy Viewer:查看視圖樹的工具
記憶體最佳化
(1)Bitmap最佳化
使用適當解析度和大小的圖片;
及時回收記憶體:從Android 3.0開始,Bitmap被放置到了堆中,其記憶體由GC管理,所以不用手動調用bitmap.recycle()方法進行釋放了;
使用圖片緩衝:設計記憶體緩衝和磁碟緩衝可以更好地利用Bitmap。
(2)代碼最佳化
使用靜態方法,它比普通方法會提高15%左右的訪問速度;
盡量不要使用枚舉,少用迭代器;
對Cursor、Receiver、Sensor、File等對象,要非常注意對它們的建立、回收與註冊、解註冊;
使用SurfaceView來替代view進行大量的、頻繁的繪圖操作;
盡量使用視圖緩衝,而不是每次都執行inflate方法解析視圖。
怎麼加速啟動Activity
Android效能最佳化之加快應用啟動速度
Android效能最佳化之Splash頁應該這樣設計
啟動方式
通常來說,在安卓中應用的啟動方式分為兩種:冷啟動和暖開機。
1、冷啟動:當啟動應用時,後台沒有該應用的進程,這時系統會重新建立一個新的進程分配給該應用,這個啟動方式就是冷啟動。
2、暖開機:當啟動應用時,後台已有該應用的進程(例:按back鍵、home鍵,應用雖然會退出,但是該應用的進程是依然會保留在後台,可進入工作清單查看),所以在已有進程的情況下,這種啟動會從已有的進程中來啟動應用,這個方式叫暖開機。
特點
1、冷啟動:冷啟動因為系統會重新建立一個新的進程分配給它,所以會先建立和初始化Application類,再建立和初始化MainActivity類(包括一系列的測量、布局、繪製),最後顯示在介面上。
2、暖開機:暖開機因為會從已有的進程中來啟動,所以暖開機就不會走Application這步了,而是直接走MainActivity(包括一系列的測量、布局、繪製),所以暖開機的過程只需要建立和初始化一個MainActivity就行了,而不必建立和初始化Application,因為一個應用從新進程的建立到進程的銷毀,Application只會初始化一次。
應用啟動的流程
在安卓系統上,應用在沒有進程的情況下,應用的啟動都是這樣一個流程:當點擊app的啟動表徵圖時,安卓系統會從Zygote(|za?g??t|受精卵)進程中fork建立出一個新的進程分配給該應用,之後會依次建立和初始化Application類、建立MainActivity類、載入主題樣式Theme中的windowBackground等屬性設定給MainActivity以及配置Activity層級上的一些屬性、再inflate布局、當onCreate/onStart/onResume方法都走完了後最後才進行contentView的measure/layout/draw顯示在介面上,所以直到這裡,應用的第一次啟動才算完成,這時候我們看到的介面也就是所說的第一幀。
所以,總結一下,應用的啟動流程如下:
Application的構造器方法——>attachBaseContext()——>onCreate()——>Activity的構造方法——>onCreate()——>配置主題中背景等屬性——>onStart()——>onResume()——>測量布局繪製顯示在介面上。
OOM 問題如何處理
http://blog.csdn.net/wangqilin8888/article/details/7752528
圖片OOM處理方法:Android高效載入大圖、多圖解決方案,有效避免程式OOM
a.對高分辨的圖片進行壓縮
b.使用圖片緩衝技術,最核心的類是LruCache
OOM主要原因有兩個:
1.由於我們程式的失誤,長期保持某些資源(如Context)的引用,造成記憶體泄露,資源造成得不到釋放。
2. 儲存了多個耗用記憶體過大的對象(如Bitmap),造成記憶體超出限制。
針對圖片過大的OOM的解決方案:
1)高效載入大圖片,利用圖片壓縮。
我們怎樣才能對圖片進行壓縮呢?通過設定BitmapFactory.Options中inSampleSize的值就可以實現。比如我們有一張2048*1536像素的圖片,將inSampleSize的值設定為4,就可以把這張圖片壓縮成512*384像素。原本載入這張圖片需要佔用13M的記憶體,壓縮後就只需要佔用0.75M了(假設圖片是ARGB_8888類型,即每個像素點佔用4個位元組)。
2)利用圖片緩衝技術
記憶體緩衝技術對那些大量佔用應用程式寶貴記憶體的圖片提供了快速存取的方法。其中最核心的類是LruCache (此類在android-support-v4的包中提供) 。這個類非常適合用來緩衝圖片,它的主要演算法原理是把最近使用的對象用強引用儲存在 LinkedHashMap 中,並且把最近最少使用的對象在緩衝值達到預設定值之前從記憶體中移除。
記憶體溢出問題如何處理
1.使用更加輕量的資料結構
例如,我們可以考慮使用ArrayMap/SparseArray而不是HashMap等傳統資料結構。通常的HashMap的實現方式更加消耗記憶體,因為它需要一個額外的執行個體對象來記錄Mapping操作。另外,SparseArray更加高效,在於他們避免了對key與value的自動裝箱(autoboxing),並且避免了裝箱後的解箱。
2.避免在Android裡面使用Enum
Android官方培訓課程提到過“Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.”,具體原理請參考《Android效能最佳化典範(三)》,所以請避免在Android裡面使用到枚舉。
3.減小Bitmap對象的記憶體佔用
Bitmap是一個極容易消耗記憶體的大胖子,減小建立出來的Bitmap的記憶體佔用可謂是重中之重,,通常來說有以下2個措施:
inSampleSize:縮放比例,在把圖片載入記憶體之前,我們需要先計算出一個合適的縮放比例,避免不必要的大圖載入。
decode format:解碼格式,選擇ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差異
4.Bitmap對象的複用
縮小Bitmap的同時,也需要提高BitMap對象的複用率,避免頻繁建立BitMap對象,複用的方法有以下2個措施
LRUCache:“最近最少使用演算法”在Android中有極其普遍的應用。ListView與GridView等顯示大量圖片的控制項裡,就是使用LRU的機制來緩衝處理好的Bitmap,把近期最少使用的資料從緩衝中移除,保留使用最頻繁的資料,
inBitMap進階特性:利用inBitmap的進階特性提高Android系統在Bitmap分配與釋放執行效率。使用inBitmap屬性可以告知Bitmap解碼器去嘗試使用已經存在的記憶體地區,新解碼的Bitmap會嘗試去使用之前那張Bitmap在Heap中所佔據的pixel data記憶體地區,而不是去問記憶體重新申請一塊地區來存放Bitmap。利用這種特性,即使是上千張的圖片,也只會僅僅只需要佔用螢幕所能夠顯示的圖片數量的記憶體大小
5.使用更小的圖片
在涉及給到資源圖片時,我們需要特別留意這張圖片是否存在可以壓縮的空間,是否可以使用更小的圖片。盡量使用更小的圖片不僅可以減少記憶體的使用,還能避免出現大量的InflationException。假設有一張很大的圖片被XML檔案直接引用,很有可能在初始化視圖時會因為記憶體不足而發生InflationException,這個問題的根本原因其實是發生了OOM。
6.StringBuilder
在有些時候,代碼中會需要使用到大量的字串拼接的操作,這種時候有必要考慮使用StringBuilder來替代頻繁的“+”。
7.避免在onDraw方法裡面執行對象的建立
類似onDraw等頻繁調用的方法,一定需要注意避免在這裡做建立對象的操作,因為他會迅速增加記憶體的使用,而且很容易引起頻繁的gc,甚至是記憶體抖動。
8.避免對象的記憶體泄露
https://drakeet.me/android-leaks
Android效能最佳化之常見的記憶體流失
·類的靜態變數持有大資料對象
靜態變數長期維持到大資料對象的引用,阻止記憶體回收。
·非靜態內部類存在靜態執行個體
非靜態內部類會維持一個到外部類執行個體的引用,如果非靜態內部類的執行個體是靜態,就會間接長期維持著外部類的引用,阻止被回收掉。
·資來源物件未關閉
資源性對象比如(Cursor,File檔案等)往往都用了一些緩衝,我們在不使用的時候,應該及時關閉它們, 以便它們的緩衝及時回收記憶體。它們的緩衝不僅存在於java虛擬機器內,還存在於java虛擬機器外。 如果我們僅僅是把它的引用設定為null,而不關閉它們,往往會造成記憶體泄露。
解決辦法: 比如SQLiteCursor(在解構函式finalize(),如果我們沒有關閉它,它自己會調close()關閉), 如果我們沒有關閉它,系統在回收它時也會關閉它,但是這樣的效率太低了。 因此對於資源性對象在不使用的時候,應該調用它的close()函數,將其關閉掉,然後才置為null. 在我們的程式退出時一定要確保我們的資源性對象已經關閉。 程式中經常會進行查詢資料庫的操作,但是經常會有使用完畢Cursor後沒有關閉的情況。如果我們的查詢結果集比較小, 對記憶體的消耗不容易被發現,只有在常時間大量操作的情況下才會複現記憶體問題,這樣就會給以後的測試和問題排查帶來困難和風險,記得try catch後,在finally方法中關閉串連
Handler記憶體流失(?)
Handler作為內部類存在於Activity中,但是Handler生命週期與Activity生命週期往往並不是相同的,比如當Handler對象有Message在排隊,則無法釋放,進而導致本該釋放的Acitivity也沒有辦法進行回收。
解決辦法:
1.聲明handler為static類,這樣內部類就不再持有外部類的引用了,就不會阻塞Activity的釋放
2.如果內部類實在需要用到外部類的對象,可在其內部聲明一個弱引用引用外部類。
public class MainActivity extends Activity {private CustomHandler mHandler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); mHandler = new CustomHandler(this); }static class CustomHandlerextends Handler {// 內部聲明一個弱引用,引用外部類private WeakReference<MainActivity > activityWeakReference;public MyHandler(MyActivity activity) { activityWeakReference= new WeakReference<MainActivity >(activity); }// ... ... }}
3.在Activity onStop或者onDestroy的時候,取消掉該Handler對象的Message和Runnable
@Overridepublic void onDestroy() {// If null, all callbacks and messages will be removed. mHandler.removeCallbacksAndMessages(null);}
·一些不良代碼習慣
有些代碼並不造成記憶體泄露,但是他們的資源沒有得到重用,頻繁的申請記憶體和銷毀記憶體,消耗CPU資源的同時,也引起記憶體抖動
解決方案
如果需要頻繁的申請記憶體對象和和釋放對象,可以考慮使用對象池來增加對象的複用。 例如ListView便是採用這種思想,通過複用converview來避免頻繁的GC
Android 效能最佳化