2010-06-13 3 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은 메모리 누수를 나타내는 :

((여기서 코드는 getApplication()) setBitmapX (BitmapFactory.decodeByteArray ((byte []) args [0], 0, ((byte []) args [0]).

어떤 제안이 있어도 감사드립니다. 미리 감사드립니다.

+0

세미 추측을 시도 할 수 있습니다 : 당신이'를 호출해야한다 귀하의'Bitmap' 객체에 재활용을()'당신이 그들과 함께 완료 후? 또한 'PickerActivity.this'에 대한 호출은 사용자가 지정한 컨텍스트에서 의미가없는 것처럼 보입니다. 그리고 자주 사용되는'(myApp) getApplication()'호출을 캐시해야합니다. –

+0

Christopher, 답장을 보내 주셔서 감사합니다. 실제로 PickerActivity는 MyActivity입니다 (게시물을 편집했습니다). 비트 맵은 응용 프로그램 수준에서 정의됩니다. 그 이유는 내가 후속 작업에서 필요하기 때문에 그들을 재활용하지 않기 때문입니다. 응용 프로그램과 MemoryAnalyzer를 디버깅하면 MyActivity가 종료 된 경우에도 ManageCaptureTask가 지속된다는 것을 알 수 있습니다.이 작업은 수행 방법을 모르는 것입니다. 즉, 비동기 작업을 종료하십시오. 나는 게시물을 편집하고 MyActivity가 종료되고 다음 활동이 시작되는 onClick 이벤트를 추가했습니다. – Manu

+0

나는'Application'에서'Bitmap'을 사용하고있는 것을 보았습니다 만, 어떤 시점에서 이것을'null'로 설정하는 것을 보았습니다. 그래서 그 부분에서 재활용되어야하는지 의아해했습니다. –

답변

10

onPostExecute가 호출 된 후 스레드가 가비지 수집되었거나 여전히 메모리에 있습니까?

비동기 작업은 작업이 닫히는 순간 취소되거나 파괴되지 않습니다. 스레드가 다소 가벼운 경우 약간의 시간이 지나면 완료되고 계속 실행하고 MyActivity.this를 추가하십시오. onPostExecute() 메소드의 isFinishing() 절.

당신의 작업은 MyActivity 활동에 대한 암시 적 참조를 저장합니다. 이것은 활동 내 개인 클래스이기 때문입니다. 즉, 작업이 종료 될 때까지 Activity가 가비지 수집되지 않습니다.

+0

Janusz, "귀하의 작업 MyActivity.this에 대한 암시 적 참조를 저장합니다"에 대해 알고 있었지만 아직 관리 방법을 알지 못했습니다. 나는 당신의 제안을 "onPostExecuteMethod에 MyActivity.this.isFinishing() 절을 추가"하고 피드를 다시 게시 할 것입니다. 다시 감사합니다! – Manu

+0

@Manu가이 문제를 해결 했습니까? –

+0

@Hisoka 예. – Manu

0

당신은 코드 아래

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