Android 記憶體流失最佳化總結

來源:互聯網
上載者:User

標籤:des   android   blog   http   ar   io   os   使用   sp   

android記憶體泄露最佳化總結 部落格分類: android
android記憶體溢出OutOfMemoryError .
android手機給應用程式指派的記憶體通常是8兆左右,如果處理記憶體處理不當很容易造成OutOfMemoryError,我們的產品出現最多的錯誤也是OutOfMemoryError的異常,
在解決這個異常時在網上發現很多關於OutOfMemoryError的原因的介紹。
OutOfMemoryError主要由以下幾種情況造成:
1.資料庫的cursor沒有關閉。  
操作Sqlite資料庫時,Cursor是資料庫表中每一行的集合,Cursor提供了很多方法,可以很方便的讀取資料庫中的值,
    可以根據索引,列名等擷取資料庫中的值,通過遊標的方式可以調用moveToNext()移到下一行
    當我們操作完資料庫後,一定要記得調用Cursor對象的close()來關閉遊標,釋放資源。
2.構造adapter沒有使用緩衝contentview。
    在繼承BaseAdapter時會讓我們重寫getView(int position, View   convertView, ViewGroup parent)方法,
    第二個參數convertView就是我們要用到的重用的對象

Java代碼  
[email protected]  
2.public View getView(int position, View convertView, ViewGroup parent) {   
3.    ViewHolder vHolder = null;   
4.               //如果convertView對象為空白則建立新對象,不為空白則複用   
5.    if (convertView == null) {   
6.        convertView = inflater.inflate(..., null);   
7.        // 建立 ViewHodler 對象   
8.        vHolder = new ViewHolder();   
9.        vHolder.img= (ImageView) convertView.findViewById(...);   
10.        vHolder.tv= (TextView) convertView   
11.                .findViewById(...);   
12.        // 將ViewHodler儲存到Tag中   
13.        convertView.setTag(vHolder);   
14.    } else {   
15.                       //當convertView不為空白時,通過getTag()得到View   
16.        vHolder = (ViewHolder) convertView.getTag();   
17.    }   
18.    // 給對象賦值,修改顯示的值   
19.    vHolder.img.setImageBitmap(...);   
20.    vHolder.tv.setText(...);   
21.    return convertView;   
22.}   
23.       //將顯示的View 封裝成類   
24.static class ViewHolder {   
25.    TextView tv;   
26.    ImageView img;   
27.}  
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder vHolder = null;
                //如果convertView對象為空白則建立新對象,不為空白則複用
        if (convertView == null) {
            convertView = inflater.inflate(..., null);
            // 建立 ViewHodler 對象
            vHolder = new ViewHolder();
            vHolder.img= (ImageView) convertView.findViewById(...);
            vHolder.tv= (TextView) convertView
                    .findViewById(...);
            // 將ViewHodler儲存到Tag中
            convertView.setTag(vHolder);
        } else {
                        //當convertView不為空白時,通過getTag()得到View
            vHolder = (ViewHolder) convertView.getTag();
        }
        // 給對象賦值,修改顯示的值
        vHolder.img.setImageBitmap(...);
        vHolder.tv.setText(...);
        return convertView;
    }
        //將顯示的View 封裝成類
    static class ViewHolder {
        TextView tv;
        ImageView img;
    }
    這裡只講使用方法,具體效能測試文章請見:
    ListView中getView的原理+如何在ListView中放置多個item
    http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html
    Android開發之ListView適配器(Adapter)最佳化
    http://shinfocom.iteye.com/blog/1231511
3.調用registerReceiver()後未調用unregisterReceiver().
     廣播接收者(BroadcastReceiver)經常在應用中用到,可以在多線程任務完成後發送廣播通知UI更新,也可以接收系統廣播實現一些功能
     可以通過代碼的方式註冊:
    IntentFilter postFilter = new IntentFilter();
    postFilter.addAction(getPackageName() + ".background.job");
    this.registerReceiver(receiver, postFilter);
    當我們Activity中使用了registerReceiver()方法註冊了BroadcastReceiver,一定要在Activity的生命週期內調用unregisterReceiver()方法取消註冊
    也就是說registerReceiver()和unregisterReceiver()方法一定要成對出現,通常我們可以重寫Activity的onDestory()方法:

Java代碼  
[email protected]  
2.protected void onDestroy() {   
3.      this.unregisterReceiver(receiver);   
4.      super.onDestroy();   
5.}  
    @Override
    protected void onDestroy() {
          this.unregisterReceiver(receiver);
          super.onDestroy();
    }
4.未關閉InputStream/OutputStream。
    這個就不多說了,我們操作完輸入輸出資料流都要關閉流
5.Bitmap使用後未調用recycle()。
    圖片處理不好是造成記憶體溢出的又一個頭號原因,(在我們的產品中也有體現),

    當我們處理完圖片之後可以通過調用recycle()方法來回收圖片對象


Java代碼  
1.if(!bitmap.isRecycled())   
2.{   
3.    bitmap.recycle()   
4.}          
        if(!bitmap.isRecycled())
        {
            bitmap.recycle()
        }        

    除此之外:
    直接使用ImageView顯示bitmap會佔用較多資源,特別是圖片較大的時候,可能導致崩潰。
    使用BitmapFactory.Options設定inSampleSize, 這樣做可以減少對系統資源的要求。
    屬性值inSampleSize表示縮圖大小為原始圖片大小的幾分之一,即如果這個值為2,則取出的縮圖的寬和高都是原始圖片的1/2,圖片大小就為原始大小的1/4。
        BitmapFactory.Options bitmapFactoryOptions = new BitmapFactory.Options();  
        bitmapFactoryOptions.inJustDecodeBounds = true;  
        bitmapFactoryOptions.inSampleSize = 2;  
        // 這裡一定要將其設定回false,因為之前我們將其設定成了true  
        // 設定inJustDecodeBounds為true後,decodeFile並不分配空間,即,BitmapFactory解碼出來的Bitmap為Null,但可計算出原始圖片的長度和寬度  
        options.inJustDecodeBounds = false;
        Bitmap bmp = BitmapFactory.decodeFile(sourceBitmap, options);  
6.Context泄漏。
    這是一個很隱晦的OutOfMemoryError的情況。先看一個Android官網提供的例子:

Java代碼  
1.private static Drawable sBackground;   
[email protected]  
3.protected void onCreate(Bundle state) {   
4.  super.onCreate(state);   
5.  
6.  TextView label = new TextView(this);   
7.  label.setText("Leaks are bad");   
8.  
9.  if (sBackground == null) {   
10.    sBackground = getDrawable(R.drawable.large_bitmap);   
11.  }   
12.  label.setBackgroundDrawable(sBackground);   
13.  
14.  setContentView(label);   
15.}  
private static Drawable sBackground;
@Override
protected void onCreate(Bundle state) {
  super.onCreate(state);

  TextView label = new TextView(this);
  label.setText("Leaks are bad");

  if (sBackground == null) {
    sBackground = getDrawable(R.drawable.large_bitmap);
  }
  label.setBackgroundDrawable(sBackground);

  setContentView(label);
}

    這段代碼效率很快,但同時又是極其錯誤的;
    在第一次螢幕方向切換時它泄露了一開始建立的Activity。當一個Drawable附加到一個 View上時,
    View會將其作為一個callback設定到Drawable上。上述的程式碼片段,意味著Drawable擁有一個TextView的引用,
    而TextView又擁有Activity(Context類型)的引用,換句話說,Drawable擁有了更多的對象引用。即使Activity被 銷毀,記憶體仍然不會被釋放。
    另外,對Context的引用超過它本身的生命週期,也會導致Context泄漏。所以盡量使用Application這種Context類型。
    這種Context擁有和應用程式一樣長的生命週期,並且不依賴Activity的生命週期。如果你打算儲存一個長時間的對象,
    並且其需要一個 Context,記得使用Application對象。你可以通過調用Context.getApplicationContext()或 Activity.getApplication()輕鬆得到Application對象。
    最近遇到一種情況引起了Context泄漏,就是在Activity銷毀時,裡面有其他線程沒有停。
    總結一下避免Context泄漏應該注意的問題:
    1.使用Application這種Context類型。
    2.注意對Context的引用不要超過它本身的生命週期。
    3.謹慎的使用“static”關鍵字。
    4.Context裡如果有線程,一定要在onDestroy()裡及時停掉。
7.static關鍵字
    當類的成員變數聲明成static後,它是屬於類的而不是屬於對象的,如果我們將很大的資來源物件(Bitmap,context等)聲明成static,那麼這些資源不會隨著對象的回收而回收,
    會一直存在,所以在使用static關鍵字定義成員變數的時候要謹慎。

Android 記憶體流失最佳化總結

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.