天天看點

Android開發優化之——從代碼角度進行優化(轉載)

出處:http://blog.csdn.net/arui319/article/details/8537588

通常我們寫程式,都是在項目計劃的壓力下完成的,此時完成的代碼可以完成具體業務邏輯,但是性能不一定是最優化的。一般來說,優秀的程式員在寫完代碼之後都會不斷的對代碼進行重構。重構的好處有很多,其中一點,就是對代碼進行優化,提高軟體的性能。下面我們就從幾個方面來了解Android開發過程中的代碼優化。

1)靜态變量引起記憶體洩露

在代碼優化的過程中,我們需要對代碼中的靜态變量特别留意。靜态變量是類相關的變量,它的生命周期是從這個類被聲明,到這個類徹底被垃圾回收器回收才會被銷毀。是以,一般情況下,靜态變量從所在的類被使用開始就要一直占用着記憶體空間,直到程式退出。如果不注意,靜态變量引用了占用大量記憶體的資源,造成垃圾回收器無法對記憶體進行回收,就可能造成記憶體的浪費。

先來看一段代碼,這段代碼定義了一個Activity。

private static Resources mResources; 

@Override

protected void onCreate(Bundle state) {

super.onCreate(state);

if (mResources == null) {

    mResources = this.getResources();

    }

}

這段代碼中有一個靜态的Resources對象。代碼片段mResources = this.getResources()對Resources對象進行了初始化。這時Resources對象擁有了目前Activity對象的引用,Activity又引用了整個頁面中所有的對象。

如果目前的Activity被重新建立(比如橫豎屏切換,預設情況下整個Activity會被重新建立),由于Resources引用了第一次建立的Activity,就會導緻第一次建立的Activity不能被垃圾回收器回收,進而導緻第一次建立的Activity中的所有對象都不能被回收。這個時候,一部分記憶體就浪費掉了。

經驗分享:

在實際項目中,我們經常會把一些對象的引用加入到集合中,如果這個集合是靜态的話,就需要特别注意了。當不需要某對象時,務必及時把它的引用從集合中清理掉。或者可以為集合提供一種更新政策,及時更新整個集合,這樣可以保證集合的大小不超過某值,避免記憶體空間的浪費。

    2)使用Application的Context

在Android中,Application Context的生命周期和應用的生命周期一樣長,而不是取決于某個Activity的生命周期。如果想保持一個長期生命的對象,并且這個對象需要一個Context,就可以使用Application對象。可以通過調用Context.getApplicationContext()方法或者Activity.getApplication()方法來獲得Application對象。

依然拿上面的代碼作為例子。可以将代碼修改成下面的樣子。

private static Resources mResources; 

@Override

protected void onCreate(Bundle state) {

super.onCreate(state);

if (mResources == null) {

    // mResources = this.getResources();

    mResources = this.getApplication().getResources();

    }

}

    在這裡将this.getResources()修改為this.getApplication().getResources()。修改以後,Resources對象擁有的是Application對象的引用。如果Activity被重新建立,第一次建立的Activity就可以被回收了。

3)及時關閉資源

Cursor是Android查詢資料後得到的一個管理資料集合的類。正常情況下,如果我們沒有關閉它,系統會在回收它時進行關閉,但是這樣的效率特别低。如果查詢得到的資料量較小時還好,如果Cursor的資料量非常大,特别是如果裡面有Blob資訊時,就可能出現記憶體問題。是以一定要及時關閉Cursor。

下面給出一個通用的使用Cursor的代碼片段。

Cursor cursor = null;

try{

    cursor = mContext.getContentResolver().query(uri,null,null,null,null);

    if (cursor != null) {

        cursor.moveToFirst();

        // 處理資料

    }

} catch (Exception e){

    e.printStatckTrace();

} finally {

    if (cursor != null){

        cursor.close();

    }

}

即對異常進行捕獲,并且在finally中将cursor關閉。

同樣的,在使用檔案的時候,也要及時關閉。

4)使用Bitmap及時調用recycle()

前面的章節講過,在不使用Bitmap對象時,需要調用recycle()釋放記憶體,然後将它設定為null。雖然調用recycle()并不能保證立即釋放占用的記憶體,但是可以加速Bitmap的記憶體的釋放。

在代碼優化的過程中,如果發現某個Activity用到了Bitmap對象,卻沒有顯式的調用recycle()釋放記憶體,則需要分析代碼邏輯,增加相關代碼,在不再使用Bitmap以後調用recycle()釋放記憶體。

    5)對Adapter進行優化

下面以構造ListView的BaseAdapter為例說明如何對Adapter進行優化。

在BaseAdapter類中提供了如下方法:

public View getView(int position, View convertView, ViewGroup parent)

當ListView清單裡的每一項顯示時,都會調用Adapter的getView方法傳回一個View,

來向ListView提供所需要的View對象。

下面是一個完整的getView()方法的代碼示例。

public View getView(int position, View convertView, ViewGroup parent) {

  ViewHolder holder;

if (convertView == null) {

      convertView = mInflater.inflate(R.layout.list_item, null);

      holder = new ViewHolder();

      holder.text = (TextView) convertView.findViewById(R.id.text);

      convertView.setTag(holder);

  } else {

      holder = (ViewHolder) convertView.getTag();

  }

  holder.text.setText("line" + position);

  return convertView;

}

private class ViewHolder {

  TextView text;

}

當向上滾動ListView時,getView()方法會被反複調用。getView()的第二個參數convertView是被緩存起來的List條目中的View對象。當ListView滑動的時候,getView可能會直接傳回舊的convertView。這裡使用了convertView和ViewHolder,可以充分利用緩存,避免反複建立View對象和TextView對象。

如果ListView的條目隻有幾個,這種技巧并不能帶來多少性能的提升。但是如果條目有幾百甚至幾千個,使用這種技巧隻會建立幾個convertView和ViewHolder(取決于目前界面能夠顯示的條目數),性能的差别就非常非常大了。

    6)代碼“微優化”

    當今時代已經進入了“微時代”。這裡的“微優化”指的是代碼層面的細節優化,即不改動代碼整體結構,不改變程式原有的邏輯。盡管Android使用的是Dalvik虛拟機,但是傳統的Java方面的代碼優化技巧在Android開發中也都是适用的。

下面簡要列舉一部分。因為一般Java開發者都能夠了解,就不再做具體的代碼說明。

建立新的對象都需要額外的記憶體空間,要盡量減少建立新的對象。

将類、變量、方法等等的可見性修改為最小。

針對字元串的拼接,使用StringBuffer替代String。

不要在循環當中聲明臨時變量,不要在循環中捕獲異常。

如果對于線程安全沒有要求,盡量使用線程不安全的集合對象。

使用集合對象,如果事先知道其大小,則可以在構造方法中設定初始大小。

檔案讀取操作需要使用緩存類,及時關閉檔案。

慎用異常,使用異常會導緻性能降低。

如果程式會頻繁建立線程,則可以考慮使用線程池。

經驗分享:

代碼的微優化有很多很多東西可以講,小到一個變量的聲明,大到一段算法。尤其在代碼Review的過程中,可能會反複審查代碼是否可以優化。不過我認為,代碼的微優化是非常耗費時間的,沒有必要從頭到尾将所有代碼都優化一遍。開發者應該根據具體的業務邏輯去專門針對某部分代碼做優化。比如應用中可能有一些方法會被反複調用,那麼這部分代碼就值得專門做優化。其它的代碼,需要開發者在寫代碼過程中去注意。

優化系列相關博文:

Android開發優化之——對Bitmap的記憶體優化

Android開發優化之——使用軟引用和弱引用

Android開發優化之——從代碼角度進行優化

Android開發優化之——對界面UI的優化(1)

Android開發優化之——對界面UI的優化(2)

Android開發優化之——對界面UI的優化(3)