2011-03-18 135 views
3

我正在工作的應用程序泄漏內存。據我所知,我正在做的一切建議在:http://developer.android.com/resources/articles/avoiding-memory-leaks.html內存泄漏非常簡單的應用程序

我已經削減我的應用程序下降到一個非常簡單的應用程序,什麼都不做,但設置背景圖像。每次我進行屏幕方向更改時,應用程序都會泄漏30k-50k的內存。

所以我懷疑如下:

的setContentView() 和 findViewById()

我需要做的東西在的onDestroy()有關這些調用,從去耦活動?

另外我有幾個問題。在onDestroy()我調用setBackgroundResource(0)。我相信如果我不這樣做,背景位圖的Drawable將保持對視圖的回調,這會導致整個上下文的泄漏。這是真的?將這個調用添加到onDestroy()當然似乎對泄漏的大小有很大的影響。在視圖構造函數中,我嘗試通過使用Application上下文進行super()調用,而不是活動上下文來移除對活動的一些引用。這實際上是否提供這種好處,或者它有什麼關係?是否有這樣的副作用,我應該知道?

代碼和XML如下:在這一點上,我真的不明白爲什麼它應該泄漏內存。任何啓發將不勝感激。

MemLeak.java

package randombrand.MemLeak; 

import randombrand.MemLeak.R; 
import randombrand.MemLeak.MLView; 
import android.app.Activity; 
import android.os.Bundle; 
import android.util.Log; 

public class MemLeak extends Activity { 

    private MLView mmlView; 
    private static final String strmlBundle = "Mem Leak"; 

    @Override 
    public void onCreate(Bundle icicle) { 
     super.onCreate(icicle); 
     setContentView(R.layout.memleak_layout); 
     mmlView = (MLView) findViewById(R.id.viewMemLeak); 
     try { 
      mmlView.Init(this); 
      SetBackgroundBitmap(); 
     } catch (Exception ex) { 
      Log.e(strmlBundle, "Failed to launch Mem Leak." + ex); 
      this.finish(); 
     } 
     if (icicle == null) { 
      mmlView.SetActive(true); 
     } else { 
      Bundle bundle = icicle.getBundle(strmlBundle); 
      if (bundle != null) { 
       mmlView.SetActive(true); 
       mmlView.invalidate(); 
      } else { 
       mmlView.SetActive(false); 
      } 
     } 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
     mmlView.SetActive(false); 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     mmlView.SetActive(true); 
    } 

    private void SetBackgroundBitmap() { 
     mmlView.setBackgroundResource(R.drawable.dark_background); 
    } 

    @Override 
    public void onDestroy() { 
     super.onDestroy(); 
     mmlView.setBackgroundResource(0); 
    } 
} 

MLView.java

package randombrand.MemLeak; 

import android.content.Context; 
import android.graphics.Canvas; 
import android.os.Handler; 
import android.os.Message; 
import android.util.AttributeSet; 
import android.view.View; 

public class MLView extends View { 

    private static final long ltFpDrawDelay = 66; 
    Context mContextApp; 
    // true when we are not sleeping in the background 
    private boolean mfActive = false; 

    public MLView(Context context, AttributeSet aSet) { 
     super(context.getApplicationContext(), aSet); 
    } 

    public MLView(Context context, AttributeSet aSet, int nStyle) { 
     super(context.getApplicationContext(), aSet, nStyle); 
    } 

    public void Init(MemLeak mLeak) { 
     mContextApp = mLeak.getApplicationContext(); 
     SetActive(true); 
    } 

    public void Update() { 
     mRedrawHandler.sleep(ltFpDrawDelay); 
    } 

    public void SetActive(boolean fActive) { 
     mfActive = fActive; 
     if (fActive) Update(); 
    } 

    @Override 
    public void onDraw(Canvas canvas) { 
     super.onDraw(canvas); 
    } 

    private RedrawHandler mRedrawHandler = new RedrawHandler(); 

    class RedrawHandler extends Handler { 

     @Override 
     public void handleMessage(Message msg) { 
      MLView.this.Update(); 
      MLView.this.invalidate(); 
     } 

     public void sleep(long ltMillis) { 
      this.removeMessages(0); 
      sendMessageDelayed(obtainMessage(0), ltMillis); 
     } 
    } 
} 

memleak_layout.java

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"> 

    <randombrand.MemLeak.MLView 
     android:id="@+id/viewMemLeak" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" /> 

</FrameLayout>  

的AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
     package="randombrand.MemLeak" 
     android:versionCode="1" 
     android:versionName="1.0"> 
    <uses-sdk android:minSdkVersion="5" /> 

    <application android:icon="@drawable/icon" android:label="@string/app_name" 
      android:debuggable="true"> 
     <activity android:name="MemLeak" 
       android:launchMode="singleInstance" 
       android:label="@string/app_name"> 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" /> 
       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 
    </application> 
</manifest> 
+0

請仔細閱讀前面的問題,並通過選中旁邊的複選框將最佳答案標記爲正確答案。 – 2011-03-18 19:11:54

+0

我知道這是一個古老的問題,但會取消onDestroy幫助中的視圖?如在'mmlView = null;'中。你爲什麼在你的視圖中使用'context.getApplicationContext()'?一定是這樣嗎? – 2013-11-25 14:52:02

回答

1

jbww,

我在我的一些活動中注意到類似的行爲,所以我說

android:configChanges="keyboardHidden|orientation" 

AndroidManifest.xmlActivity然後通過重寫重新加載必要的信息。

我不再注意到每次旋轉設備時都會增加堆。

我希望這也適用於你。

+0

非常感謝,這似乎工作。我所做的只是將更改添加到清單。我實際上並沒有重寫onConfigurationChanged(),因爲我的應用程序沒有任何需要做的事情,因爲它尚未在onCreate()中執行。 – jbww 2011-03-18 21:45:23

+0

任何人都可以告訴我Android中的可疑錯誤嗎? – jbww 2011-03-18 21:46:34