android設備作爲一種移動設備,不管是內存還是CPU的性能都收到了一定的限制,無法做到像PC設備那樣具有超大的內存和高性能的CPU。鑑於這一點,這也意味着android程序不可能無限制的使用內存和CPU資源,過多的使用內存會導致程序內存溢出,即OOM。而過多的使用CPU資源,一般是指做出大量的耗時任務,會導致手機變的卡頓無法響應的情況,即ANR。
-
佈局優化
佈局優化的思想其實很簡單,就是儘量減少佈局文件的層級。
- 進行佈局優化,首先刪除佈局中無用的控件和層級,其次有選擇的使用性能較低的viewGroup,比如RelativeLayout。如果佈局中既可以使用LinearLayout也可以使用RelativeLayout,那麼就採用LinearLayout,這是因爲RelativeLayout功能比較複雜,它的佈局過程需要花費更多的CPU。
- 佈局優化的另一種手段就是採用 < include>標籤、< merge>標籤和ViewStub.
< include> 標籤可以將一個指定的佈局文件加載到當地的文件中。需要注意的是,如果在佈局文件中的根元素中設置了ID,而在< include>也設置了id,以標籤中的屬性爲準。
< merge>標籤一般和< include>標籤一起使用從而減少佈局的層級。如果當前佈局文件中存在一個LinearLayout,而被包含的佈局文件中也使用了LinearLayout,那麼顯然被包含的是多餘的,通過< merge>標籤可以去掉多餘的這一層LinearLayout。
ViewStub繼承了View,它非常輕量級而且寬、高都是0,因此它本身不參與任何的佈局繪製過程。ViewStub的意義在於按需加載所需的佈局文件,在實際開發中,很多佈局文件不會在正常情況不會顯示,比如網絡異常的界面,這個時候就沒必要在初始化的時候,就把該界面加載進來,通過ViewStub就可以做到在使用的時候再加載,提高了程序初始化的性能。
<ViewStub
android:id="@+id/stub_import"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/layout_network_error"
/>
以下面兩種方式進行:
findViewById(R.id.stub_impout).setVisibility(View.VISIBLE);
當ViewStub通過setVisibility方法加載後,ViewStub就會被它內部的佈局替換掉,這個時候ViewStub就不再是整個佈局結構中的一部分了。另外,目前ViewStub還不支持< merge>標籤。
- 繪製優化
繪製優化是指View的onDraw方法要避免執行大量的操作,這主要體現在兩個方面。
- 首先,onDraw中不要創建新的局部現象,這是因爲onDraw方法可能會被頻繁調用,這樣就會在一瞬間產生大量的臨時對象,這不僅佔用了過多的內存而且還會導致系統更加頻繁GC,降低了程序的執行效率。
- onDraw方法中不要做耗時的任務,也不能執行成千上萬的循環操作,儘管每次循環都很輕量級,但是大量的循環仍然十分搶佔CPU的時間片,這會照成View的繪製的不流暢。按照Google官方給出的性能優化典範中的標準,View的繪製幀率保證60fps都是最佳的,這就要求每幀的繪製時間不超過16ms(16ms = 1000/60),雖然程序很難保證16ms這個時間,但是儘量降低onDraw方法的複雜度總是切實有效的。
- 內存泄露優化
- 內存泄漏
3.1 靜態變量導致的內存泄漏
下面代碼引用了靜態mContext,導致Activity不能正常銷燬,導致內存泄漏。
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private static Context context;
@Override
protected void onCreate(Bundle saveInstanceState){
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
context = this;
}
}
3.2 單例模式導致的內存泄漏
靜態變量導致的內存泄漏都比較明顯,相應的單例模式帶來的內存泄漏是容易讓我們忽視的。
示例代碼如下:
public class SingleInstance {
private Context mContext;
private static SingleInstance instance;
private SingleInstance(Context context) {
this.mContext = context;
}
public static SingleInstance getInstance(Context context) {
if (instance == null) {
instance = new SingleInstance(context);
}
return instance;
}
public void say() {
Log.i("tag", "this is single instance");
Log.i("tag", ":code:" + instance.hashCode());
}
很明顯的原因在於引用的context對象,當在程序中被activity調用了,恰巧activity先被銷燬的情況下,因爲一直在被static所修飾的類引用,會造成內存中不能被銷燬,導致內存泄漏。
解決辦法是可以將應用的ApplicationContext賦值給SingleInstance 的Context
public static SingleInstance getInstance(Context context) {
if (instance == null) {
instance = new SingleInstance(context.getApplicationContext());
}
return instance;
}
3.3 屬性動畫導致的內存泄漏
從android3.0開始,Google提供了屬性動畫,屬性動畫中有一類無限循環的動畫,如果在activity播放此類動畫且沒有在onDestory中去停止動畫,那麼動畫會一直播放下去,儘管已經無法在界面上看到動畫效果了,並且這個時候Activity的View會被動畫持有,而View又持有了Activity,最終Activity無法釋放。
4. 響應速度優化
響應速度優化的核心思想是避免主線程中耗時操作。android中規定,activity如果5秒鐘10秒鐘之內還未執行完操作也會出現ANR。
5. 線程優化
線程優化的思想就是線程池,避免程序中存在大量的Tread。線程池可以重用內部的線程,從而避免的線程的創建和銷燬帶來的性能開銷,同時線程池還能有效的控制線程池的最大併發數,避免大量的線程因相互搶佔資源從而導致阻賽現象的對象。
6. 電池電量優化