Android 性能優化

本篇博客主要講述一下關於性能優化的方法。在開發的過程中,我們有些人只是最求功能的實現,而不去理會性能方面的問題。Android的內存和CPU的性能都是有一定限制的,過多的使用內存會導致我們的內存溢出,也就是我們常見的OOM(Out Of Memory )現象。如果過多的消耗CPU會導致我們的手機產生卡頓的現象。這些問題的產生都是由於我們在開發的過程中,一味地只求功能的實現而忽略了性能導致的。那麼我們如何避免呢?下面我們先從佈局優化開始。
Android的佈局對我們開發者來說並不陌生,我們就來談一些關於佈局的優化。一般我們的佈局初建的時候默認的是LinearLayout,如果在LinearLayouth和RelativeLayout都能實現的情況下,建議使用LinearLayouth,這是因爲LinearLayout佈局的繪製要比RelativeLayout的繪製要簡單一些。RelativeLayout的功能要比LinearLayout要複雜一些。通過佈局裏面的一些屬性我們就可以看得出LinearLayout要比RelativeLayout少得多。如果我們要實現的效果僅僅是通過LinearLayout難易實現的,需要進行佈局的嵌套的時候,此時儘量使用RelativeLayout,一旦嵌套就會導致佈局的層級增加。FramLayout和LinearLayout一樣,都是簡單的ViewGroup。
如果在我們實現功能的時候,發現很多效果基本上都是相同的,那樣的話我們就可以通過include來減少我們佈局的工作量,也可以配合merge減少層級的數量。我們就以下面的代碼爲例:
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.lyxrobert.optimize.MainActivity">
    <Button
    android:id="@+id/btn_test"
    android:text="測試"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
    <include
        layout="@layout/layout_test"></include>
</LinearLayout>

layout_test.xml

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/merge"
    android:orientation="vertical"
    android:visibility="gone"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
</merge>

include標籤和merge標籤配合使用的佈局嵌套效果
這裏寫圖片描述
將merge標籤替換成LinearLayout的佈局嵌套效果
這裏寫圖片描述
這樣對比的話你就會發現使用merge要比使用LinearLayout少一個層級。
還有就是我們一般有些控件是需要隱藏的view.setVisibility(View.INVISIBLE)或者view.setVisibility(View.GONE),當我們需要它顯示的時候我們就會設置爲view.setVisibility(View.VISIBLE);當然了這個控件的效果當然也是通用的效果,比如我們沒有網絡的時候顯示的效果,或者是沒有數據的時候顯示的效果。這些效果一般我們都會寫在一個佈局裏面,然後通過include引入,這些佈局一般默認都是隱藏的。那麼這樣的佈局還有沒有可以優化的地方呢?當然是有,我們可以通過ViewStub這個標籤在隱藏的時候減少佈局的嵌套,實現效果如下。
這裏寫圖片描述
如果設置爲顯示的狀態則爲
這裏寫圖片描述
爲什麼會出現這種情況呢?這是因爲ViewStub是一個輕量級的繼承自View,默認的寬高都是0,也就是參與任何佈局的繪製過程,當顯示的時候ViewStub的寬高就不再是0了,所以它也就參與佈局的繪製過程了。
使用ViewStub標籤是需要注意:

<ViewStub
        android:id="@+id/vs_test"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inflatedId="@+id/merge"
        android:layout="@layout/layout_test">
</ViewStub>

通過上面的代碼你會發現ViewStub引入佈局跟include是不一樣的,ViewStub引入佈局是android:layout=”@layout/layout_test”比include多了android:這一部分。否則將會報出以下錯誤

java.lang.IllegalArgumentException: ViewStub must have a valid layoutResource

爲了避免出現這樣的錯誤一定要android:layout=”@layout/layout_test”這樣設置
還有就是需要注意的是 android:id=”@+id/vs_test”這個id是ViewStub的id,而android:inflatedId=”@+id/merge”這個id是引用佈局的根佈局的id也就是merge 的id。還有就是綁定控件的時候需要注意View vs_test = ((ViewStub) findViewById(R.id.vs_test)).inflate();這樣使用會更好一些。你也可以嘗試使用ViewStub vs_test = (ViewStub) findViewById(R.id.vs_test);通過對比你就會發現一些爲啥推薦使用帶有inflate()的綁定方式了。
繪製優化
一般自定義控件的時候我們會跟onDraw這個方法打交道,我們都知道onDraw這個方法的調用是很頻繁的,尤其是我們在做一個帶有動畫效果的時候。那麼onDraw的頻繁調用我們是控制不了的,但是我們可以避免一些不必要的創建對象,否則產生的後果就是產生大量的臨時對象頻繁的調用GC機制。
還有就是不要在onDraw這個方法裏面做耗時的操作,這樣的後果就是導致界面的繪製不流暢。
內存優化
靜態變量導致的內存泄露,不要將視圖控件聲明爲static,因爲View對象會引用Activity對象,當Activity退出時其對象本身無法被銷燬,會造成內存溢出。 Bitmap是內存消耗大戶,絕大多數的OOM崩潰都是在操作Bitmap時產生的,我們需要根據需求去加載圖片的大小。例如在列表中僅用於預覽時加載縮略圖(thumbnails)。只有當用戶點擊具體條目想看詳細信息的時候,這時另啓動一個fragment/activity/對話框等等,去顯示整個圖片 ,直接使用ImageView顯示bitmap會佔用較多資源,特別是圖片較大的時候,可能導致崩潰。使用BitmapFactory.Options設置inSampleSize, 這樣做可以減少對系統資源的要求。 屬性值inSampleSize表示縮略圖大小爲原始圖片大小的幾分之一,即如果這個值爲2,則取出的縮略圖的寬和高都是原始圖片的1/2,圖片大小就爲原始大小的1/4。

BitmapFactory.Options bitmapFactoryOptions = new BitmapFactory.Options();  
bitmapFactoryOptions.inJustDecodeBounds = true;  
bitmapFactoryOptions.inSampleSize = 2;  
options.inJustDecodeBounds = false;  
Bitmap bmp = BitmapFactory.decodeFile(sourceBitmap, options); 

在使用inJustDecodeBounds時一定要注意先將裏一定要將inJustDecodeBounds設置爲true,當inJustDecodeBounds的值爲true的時候,BitmapFactory只會對圖片的寬高信息進行解析並不會去加載圖片。Android中圖片有四種屬性,分別是:ALPHA_8:每個像素佔用1byte內存,ARGB_4444:每個像素佔用2byte內存 ,ARGB_8888:每個像素佔用4byte內存 (默認),RGB_565:每個像素佔用2byte內存 ,Android默認的顏色模式爲ARGB_8888,這個顏色模式色彩最細膩,顯示質量最高。但同樣的,佔用的內存也最大。 所以在對圖片效果不是特別高的情況下使用RGB_565(565沒有透明度屬性),如下:

public static Bitmap readBitMap(Contextcontext, intresId) {  
    BitmapFactory.Optionsopt = newBitmapFactory.Options();  
    opt.inPreferredConfig = Bitmap.Config.RGB_565;  
    opt.inPurgeable = true;  
    opt.inInputShareable = true;  
    InputStreamis = context.getResources().openRawResource(resId);  
    returnBitmapFactory.decodeStream(is, null, opt);  
}  

最後就是Bitmap使用完以後要注意調用recycle()進行回收。

速度優化
不應在Application以及Activity的生命週期回調中做任何費時操作,具體指標大概是你在onCreate,onResume,onStart等回調中所花費的總時間最好不要超過400ms,否則用戶在桌面點擊你的應用圖標後,將感覺到明顯的卡頓
注意一些流的關閉
要注意管理好cursor,不要每次打開關閉cursor.因爲打開關閉Cursor非常耗時。不再使用的cursor要記得關閉(一般在finally語句塊執行)。 有一種情況下,我們不能直接將Cursor關閉掉,這就是在CursorAdapter中應用的情況,但是注意,CursorAdapter在Acivity結束時並沒有自動的將Cursor關閉掉,因此,你需要在onDestroy函數中,手動關閉,還有就是我們通常使用的IO流的關閉(一般在finally語句塊執行)。
線程的優化
在使用線程的時候要儘量使用線程池來管理線程,否則很容易產生大量的線程,造成資源的浪費。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章