2010-06-13 44 views
4

我卡住了內存泄漏,我無法修復。我使用MemoryAnalizer確定了它發生的位置,但我無法擺脫它。下面是代碼:Android:內存泄漏,由於AsyncTask

public class MyActivity extends Activity implements SurfaceHolder.Callback { 
... 

Camera.PictureCallback mPictureCallbackJpeg = new Camera.PictureCallback() { 
    public void onPictureTaken(byte[] data, Camera c) { 
     try { 
      // log the action 
      Log.e(getClass().getSimpleName(), "PICTURE CALLBACK JPEG: data.length = " + data); 

      // Show the ProgressDialog on this thread 
      pd = ProgressDialog.show(MyActivity.this, "", "Préparation", true, false); 

      // Start a new thread that will manage the capture 
      new ManageCaptureTask().execute(data, c); 
     } 
     catch(Exception e){ 
      AlertDialog.Builder dialog = new AlertDialog.Builder(MyActivity.this); 
      ... 
      dialog.create().show(); 
     } 
    } 

    class ManageCaptureTask extends AsyncTask<Object, Void, Boolean> { 
     protected Boolean doInBackground(Object... args) { 
      Boolean isSuccess = false; 

      // initialize the bitmap before the capture 
      ((myApp) getApplication()).setBitmapX(null); 
      try{ 

       // Check if it is a real device or an emulator 
       TelephonyManager telmgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 
       String deviceID = telmgr.getDeviceId(); 
       boolean isEmulator = "000000000000000".equalsIgnoreCase(deviceID); 

       // get the bitmap 
       if (isEmulator) { 
        ((myApp) getApplication()).setBitmapX(BitmapFactory.decodeFile(imageFileName)); 
       } else { 
        ((myApp) getApplication()).setBitmapX(BitmapFactory.decodeByteArray((byte[]) args[0], 0, ((byte[])args[0]).length)); 
       } 

       ((myApp) getApplication()).setImageForDB(ImageTools.resizeBmp(((myApp) getApplication()).getBmp())); 
       // convert the bitmap into a grayscale image and display it in the preview 
       ((myApp) getApplication()).setImage(makeGrayScale()); 
       isSuccess = true; 
      } 
      catch (Exception connEx){ 
       errorMessageFromBkgndThread = getString(R.string.errcapture); 
      } 
      return isSuccess; 
     } 

     protected void onPostExecute(Boolean result) { 
      // Pass the result data back to the main activity 
      if (MyActivity.this.pd != null) { 
       MyActivity.this.pd.dismiss(); 
      } 
      if (result){ 
       ((ImageView) findViewById(R.id.apercu)).setImageBitmap(((myApp) getApplication()).getBmp());  
       ((myApp) getApplication()).setBitmapX(null); 
      } 
      else{ 
       // there was an error 
       ErrAlert(); 
      } 
     } 
    }  
}; 
private void ErrAlert(){ 
    // notify the user about the error 
    AlertDialog.Builder dialog = new AlertDialog.Builder(this); 
    ... 
    dialog.create().show(); 
} 

}

活性被終止在按鈕上點擊,這樣的:

Button use = (Button) findViewById(R.id.use); 
use.setOnClickListener(new OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     Intent intent = new Intent(MyActivity.this, NextActivity.class); 
     intent.putExtra("dbID", "-1"); 
     intent.putExtra("category", category); 
     ((myApp) getApplication()).setBitmapX(null); 
     MyActivity.this.startActivity(intent); 
     MyActivity.this.finish(); 
     } 
    }); 

MemoryAnalyzer指示的存儲器泄漏於:

(( setApplication())。setBitmapX(BitmapFactory.decodeByteArray((byte [])args [0],0,((byte [])args [0])。

我很感激任何建議,謝謝您提前。

+0

半猜測:你應該可以調用'再循環()'您'Bitmap'對象你與他們完成之後? 此外,對'PickerActivity.this'的調用在您給出的上下文中似乎沒有意義。而且你應該緩存經常使用的'(myApp)getApplication()'調用。 – 2010-06-13 22:55:32

+0

克里斯托弗, 謝謝你的回覆,事實上PickerActivity是MyActivity(我編輯了這篇文章);位圖在應用程序級別定義,這就是爲什麼我不回收它們,因爲我在隨後的活動中需要它們。 調試應用程序和MemoryAnalyzer告訴我,即使MyActivity終止,ManageCaptureTask仍然存在,這是我不知道該怎麼做的:終止該異步任務。 我編輯帖子,添加onClick事件,其中MyActivity終止並啓動下一個活動。 – Manu 2010-06-14 09:06:05

+0

我看到你在'Application'中使用'Bitmap',但是在某個時候看到你把它設置爲'null',所以想知道它是否應該在那個時候回收。 – 2010-06-14 09:24:27

回答

10

onPostExecute被調用後,你的線程垃圾回收還是仍在內存中?

異動任務不會在活動解散時被取消或銷燬。如果你的線程或多或少輕量級並在一段時間後完成,只需保持它運行並添加一個MyActivity.this。在onPostExecute()方法中的isFinishing()子句。

您的任務存儲對您的活動MyActivity.this的隱式引用,因爲它是活動內部的私有類。這意味着你的活動不會被垃圾收集,直到任務退出。

+0

謝謝Janusz,我知道「你的任務存儲了你的活動MyActivity.this的隱式引用」,但我不知道如何管理它。我會嘗試你的建議「在onPostExecuteMethod中添加一個MyActivity.this.isFinishing()子句」併發佈一個反饋。再次感謝你! – Manu 2010-06-15 10:54:12

+0

@Manu是否解決了這個問題? – 2012-06-04 00:05:25

+0

@Hisoka是的。 – Manu 2012-06-09 15:05:43

0

你可以試試下面的代碼片段

protected void onPostExecute(Boolean result) { 
    if(YourActivity.this.isFinished()){ 
     //to smomething here 
    } 
}