Android 記憶體流失最佳化匯總

來源:互聯網
上載者:User

標籤:

android記憶體流失最佳化摘要 部落格分類: android
android記憶體溢出OutOfMemoryError .
android行動裝置 App程式的記憶體配置一般是8凱瑟琳約,不正確地假定處理記憶體處理非常easy建立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”keyword。
    4.Context裡假設有線程。一定要在onDestroy()裡及時停掉。


7.statickeyword
    當類成員變數聲明為static後,它屬於類而不是屬於對象。假設我們將非常大的資來源物件(Bitmap。context等待)聲明static。那麼這些資源不會被回收的回收目標。
    它會一直存在。因此,使用statickeyword成員變數定義時要小心。

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.