0

다소 큰 비트 맵을로드하고 표시하는 활동이 있습니다. 이미지 뷰에이 비트 맵의 ​​로딩은 AsyncTask를 이루어집니다오리엔테이션 변경 및 가비지 수집에서 안드로이드 메모리 누수가 발생했습니다.

private static Bitmap decodeSampledBitmapFromFile(String filepath, int reqWidth,int orientation) { 
    final BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeFile(filepath,options); 
    if(orientation==0){ 
    options.inSampleSize = calculateInSampleSizeWidth(options, reqWidth); 
    // Decode bitmap with inSampleSize set 
    options.inJustDecodeBounds = false; 
    Bitmap d = BitmapFactory.decodeFile(filepath,options); 
    return Bitmap.createScaledBitmap(d, reqWidth, d.getHeight()*reqWidth/d.getWidth(), true); 
    } 
    else{ 
     options.inSampleSize = calculateInSampleSizeHeight(options,reqWidth); 
     options.inJustDecodeBounds = false; 
     Bitmap d = BitmapFactory.decodeFile(filepath,options); 
     return Bitmap.createScaledBitmap(d, d.getWidth()*reqWidth/d.getHeight(), reqWidth, true); 
    } 
} 
private static int calculateInSampleSizeWidth(BitmapFactory.Options options, int reqWidth) { 
    int inSampleSize = 1; 
    if (options.outWidth > reqWidth) { 
     final int halfWidth = options.outWidth/2; 
     while ((halfWidth/inSampleSize) > reqWidth) { 
      inSampleSize *= 2; 
     } 
    } 
    return inSampleSize; 
} 

은 다음과 같습니다 : 위험한 처음부터 비즈니스, 그러나 우리는 아래의 표준 방법을 사용하여 BitmapFactory를 사용하여로드

private static class LoadBitmapTask extends AsyncTask<String, Void, Bitmap>{ 
    private ViewSampleActivity _activity; 
    public LoadBitmapTask(ViewSampleActivity activity){ 
     this._activity = activity; 
    } 
    public void detach(){ 
     this._activity = null; 
    } 
    @Override 
    protected Bitmap doInBackground(String... params) { 
     try{ 
      String filename = params[0]; 
      Display display = _activity.getWindowManager().getDefaultDisplay(); 
      Point size = new Point(); 
      display.getSize(size); 
      int orientation = getCameraPhotoOrientation(_activity,Uri.fromFile(new File(filename)),filename); 
      Bitmap d = null; 

      d = decodeSampledBitmapFromFile(filename, (int)(((double)size.x)*0.85),orientation); 
      d = rotateBitmapAppropriately(_activity,Uri.fromFile(new File(filename)),filename,d); 
      return d; 
     } 
     catch(Exception e){ 
      return null; 
     } 
    } 

    @Override 
    protected void onPostExecute(Bitmap result){ 
     try{ 
      _activity.sampleImageView.setImageBitmap(result); 
      _activity.sampleImageView.setVisibility(View.VISIBLE); 
      _activity.sampleImageView.getLayoutParams().height = result.getHeight(); 
      _activity.sampleImageView.getLayoutParams().width = result.getWidth(); 
      _activity.viewSampleLayout.getLayoutParams().height = LayoutParams.WRAP_CONTENT; 
      _activity.hasPicture = true; 
     } 
     catch(Exception e){ 
      e.printStackTrace(); 
     } 
    } 
} 

메모리 누수를 피하기 위해 Activity의 onStop 메서드를 오버로드하여 AsyncTask에서 활동을 분리했습니다.

@Override 
public void onStop(){ 
    if(this.loadBitmapTask!=null){ 
     loadBitmapTask.detach(); 
    } 
    super.onStop(); 
} 

이상한 동작은 처음 실행시로드가 정상적으로 작동한다는 것입니다. 오리엔테이션을 변경하면 활동이 올바르게 다시로드됩니다. 그러나 방향이 5 개 정도 변경되면 응용 프로그램이 메모리 부족 오류로 인해 중단됩니다. 비트 맵은 명백한 범인 인 것처럼 보일 것입니다. 나는 어떤 ui 요소 나 비트 맵이나 다른 것들의 정적 복사본을 저장하지 않으므로 메모리 부족 오류가 메모리 누수로 인한 것인지 궁금합니다.

해당 활동은 마지막 활동 계층입니다. 주요 활동 인 계층 구조의 루트에는 WeakReference가 포함 된 android Handler 객체와 Bluetooth 네트워킹 스레드를 관리하는 영구적 인 프래그먼트가 있습니다. 계층 구조의 두 번째 활동은 간단한 ListActivity입니다.

해당 활동의 상위 활동이이 활동에 대한 Java의 가비지 수집에 영향을 미칩니 까?

+0

오리엔테이션 변경을 통해 AsyncTask의 재 부착을 어떻게 관리합니까? –

+0

나는 아닙니다, 나는 다만 또 다른 한개를 달리고 오래된 것을 try-catch-forget 놓게하십시오. – user1843784

+0

그래서 네 번 회전하면 4 비트의 AsyncTask가 각각의 비트 맵에있을 수 있습니다. –

답변

1

decodeSampledBitmapFromFile() 방법의 Bitmap d은 가비지 수집됩니까? 나는이 개념들에 대해 100 % 명확하지 않지만, d 자체는 재활용되지 않고 d에서 스케일 된 사본을 만드는 것처럼 보인다.

AsyncTask에 죽이기보다는 다시 부착하는 것이 좋습니다 (더 많이 생성합니까?). FragmentActivity를 사용하는 경우 비 구성 인스턴스를 사용할 수 있습니다. 작업에 대한 참조를 활동에 저장하고이를 비 구성 인스턴스로 저장하십시오. 그런 활동의에서 onCreate를 다시 연결을 시도 :

private LoadBitmapTask mTask; 

@Override 
public Object onRetainCustomNonConfigurationInstance() { 
    if(mTask != null){ 
     mTask.detach(); 
    } 
    return mTask; 
} 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    mTask = (LoadBitmapTask) getLastCustomNonConfigurationInstance(); 

    if (mTask != null) { 
     mTask.attach(this); 
    } 
} 

AsyncTask를 함께 더 산란을하지 당신은 "당신이 중단 된 데리러"수있는이 방법을.

+0

위대한 솔루션, 비록 내가 함께 가지 않을 끝내지 만, 현재 구현에서 비트 맵을 다른 방향 변경에 따라 다르게 크기를 부여하고 싶습니다. 현재 구현에서는이 작업을 재활용하면 잘못된 크기가 imageView에로드 될 수 있습니다. 내가 대신 한 것은 파일에서 비트 맵을로드하기 전에 그리고 비트 맵을 회전하기 전에 작업에 대한 내 핸들이 null인지 확인하는 검사를 추가하는 것입니다. – user1843784