2011-11-08 3 views
0

메모리 누수가있는 것 같습니다. 카메라를 사용하는 목록 활동이 있습니다. 사진 찍기 만 지금 작업 중입니다 ... 하지만 일부 목록이 부풀어 오르는 경우 일부 메모리 누수가 발생하는 것 같아요. 일부 리소스를 놓친 것 같아요. 이미지 ....)OOM 예외 - VM 예산을 초과하는 비트 맵 크기

나는 그것을 발견 할 수 없었다.

정말 도움이 필요합니다. 여기

은 클래스입니다 : 리스트 활동

패키지 org.BJ.Food4All.Activities.NewRecipe;

import org.BJ.Food4All.R; 
import org.BJ.Food4All.Recipe; 
import org.BJ.Food4All.Recipe.Instruction; 
import org.BJ.Food4All.Activities.RecipeBook.RecipeInstructionsListViewAdapter; 
import org.BJ.Food4All.Activities.RecipeBook.SharedData; 
import org.BJ.Food4All.utils.CameraUtil; 
import org.BJ.Food4All.utils.ImageUploadItem; 

import android.app.ListActivity; 
import android.content.Intent; 
import android.os.Bundle; 
import android.util.Log; 
import android.view.ContextMenu; 
import android.view.MenuInflater; 
import android.view.MenuItem; 
import android.view.View; 
import android.view.ContextMenu.ContextMenuInfo; 
import android.view.View.OnClickListener; 
import android.widget.AdapterView; 
import android.widget.EditText; 

public class Instructions extends ListActivity implements OnClickListener 
{ 
    private final static String     mTAG     = "Instructions"; 
    private EditText       mInstructionEditText = null; 
    private RecipeInstructionsListViewAdapter mListViewAdapter  = null; 
    private Recipe        mEditRecipe    = PrivateResources.GetRecipe(); 

    private CameraUtil       mCameraUtil    = new CameraUtil(this); 

    private int         mSelectedEntryIndex  = -1; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.new_recipe_instruction_tab); 

     mInstructionEditText  = (EditText)findViewById(R.id.newRecipeInstructionEditTextId); 
     View addInstructionButton = findViewById(R.id.naddInstructionButtonId); 

     // Sanity check 
     if(mInstructionEditText == null || 
      addInstructionButton == null) 
     { 
      Log.e(mTAG, "NULL pointers"); 
      // secure exit 
      finish(); 
     } 

     // Set up click listeners for all the buttons 
     addInstructionButton.setOnClickListener(this); 

     mListViewAdapter = new RecipeInstructionsListViewAdapter( this, 
                     R.layout.recipes_instruction_list_single_view_entry, 
                     mEditRecipe.GetInstructions()); 

     setListAdapter(mListViewAdapter); 

     registerForContextMenu(getListView()); 
    } 

    public void onClick(View v) 
    { 
     switch(v.getId()) 
     { 
      case R.id.naddInstructionButtonId: 
       AddInstructionToRecipe(v); 
       break; 

      default: 
       Log.e(mTAG, "Invalid ID:" + v.getId()); 
       // secure exit 
       finish(); 

     } 
    } 

    private void AddInstructionToRecipe(View v) 
    { 
     String instructionText = mInstructionEditText.getText().toString(); 

     if(instructionText == null) 
     { 
      return; 
     } 

     Instruction newInstruction = new Instruction( mEditRecipe.GetInstructions().size() + 1, // Index 
                 instructionText,       // The instruction 
                 null, 
                 true); 

     if(mEditRecipe.AddInstruction(newInstruction) != true) 
     { 
      // TODO - ERROR 
     } 
     else 
     { 
      mListViewAdapter.notifyDataSetChanged(); 
     } 
    } 

    /* 
    * (non-Javadoc) 
    * @see android.app.Activity#onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo) 
    */ 
    @Override 
    public void onCreateContextMenu( ContextMenu  menu, 
             View   v, 
             ContextMenuInfo menuInfo) 
    { 
     MenuInflater inflater = getMenuInflater(); 
     inflater.inflate(R.menu.instructions_ctx_menu, menu); 

     super.onCreateContextMenu( menu, 
            v, 
            menuInfo); 
    } 

    /* 
    * (non-Javadoc) 
    * @see android.app.Activity#onContextItemSelected(android.view.MenuItem) 
    */ 
    @Override 
    public boolean onContextItemSelected(MenuItem item) 
    { 
     super.onContextItemSelected(item); 

     AdapterView.AdapterContextMenuInfo menuInfo; 
     menuInfo = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo(); 
     mSelectedEntryIndex = menuInfo.position; 

     switch(item.getItemId()) 
     { 
      case R.id.deleteId: 
       mEditRecipe.RemoveInstruction(mSelectedEntryIndex); 
       mListViewAdapter.notifyDataSetChanged(); 
       return true; 

      case R.id.takePictureId: 
       mCameraUtil.TakePicture(); 
       return true; 
     } 

     return false; 
    } 

    /* 
    * (non-Javadoc) 
    * @see android.app.Activity#onActivityResult(int, int, android.content.Intent) 
    */ 
    @Override 
    protected void onActivityResult( int  requestCode, 
             int  resultCode, 
             Intent data) 
    { 
     String imageLocation = mCameraUtil.onActivityResult( requestCode, 
                   resultCode, 
                   data); 
     // TODO - switch to parameter passed in the intent!!!! like TakePicture(index); 
     mEditRecipe.GetInstructions().get(mSelectedEntryIndex).SetInstructionImageLocation(imageLocation); 
     mSelectedEntryIndex = -1; 

     // Update the listviewitem with the picture 
     mListViewAdapter.notifyDataSetChanged(); 
    } 
} 

어댑터 대 :

package org.BJ.Food4All.Activities.RecipeBook; 

import java.util.ArrayList; 

import org.BJ.Food4All.R; 
import org.BJ.Food4All.Recipe.Instruction; 
import org.BJ.Food4All.utils.GlobalDefs; 

import android.content.Context; 
import android.graphics.Color; 
import android.graphics.Typeface; 
import android.net.Uri; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.view.ViewGroup.LayoutParams; 
import android.widget.ArrayAdapter; 
import android.widget.ImageView; 
import android.widget.ListView; 
import android.widget.TextView; 

public class RecipeInstructionsListViewAdapter extends ArrayAdapter<Instruction> 
{ 
    private  Context       mContext; 
    private  ArrayList<Instruction>   mItems; 
    private  LayoutInflater     mInflater; 

    public RecipeInstructionsListViewAdapter( Context     context, 
               int      textViewResourceId, 
               ArrayList<Instruction> items) 
    { 
     super( context, 
       textViewResourceId, 
       items); 

     mContext = context; 
     mItems  = items; 

     mInflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    } 

    @Override 
    public View getView( int   position, 
          View  convertView, 
          ViewGroup parent) 
    { 
      ViewHolder holder = new ViewHolder(); 

      if (convertView == null) 
      { 
       convertView = mInflater.inflate(R.layout.recipes_instruction_list_single_view_entry, null); 
      } 

      if(super.getItem(position) != null) 
      { 
       holder.instructionIndex = (TextView) convertView.findViewById(R.id.listUp_RecipeInstructionNumberTextBoxId); 
       holder.instructionText = (TextView) convertView.findViewById(R.id.listUp_RecipeInstructioTextTextBoxId); 
       holder.instructionImage = (ImageView)convertView.findViewById(R.id.listUp_RecipeInstructionImageViewId); 

       Typeface tf = Typeface.createFromAsset(mContext.getAssets(), "Eras_Bold.ttf"); 
       holder.instructionIndex.setTypeface(tf); 
       holder.instructionIndex.setTextSize(30); 
       holder.instructionIndex.setTextColor(GlobalDefs.GetHeadlineColor()); 
       holder.instructionIndex.setText(Integer.toString(mItems.get(position).getIndex())); 

       tf = Typeface.createFromAsset(mContext.getAssets(), "Arial.ttf"); 
       holder.instructionText.setTypeface(tf); 
       holder.instructionText.setTextSize(14); 
       holder.instructionText.setTextColor(Color.BLACK); 
       holder.instructionText.setText(mItems.get(position).getText()); 

       String imageLocation = mItems.get(position).GetInstructionImageLocation(); 
       if(imageLocation != null) 
       { 
        holder.instructionImage.setImageURI(Uri.parse(imageLocation)); 
        holder.instructionImage.setVisibility(View.VISIBLE); 
       } 
       else 
       { 
        holder.instructionImage.setVisibility(View.GONE); 
       } 

       convertView.setTag(holder); 
       convertView.setLayoutParams(new ListView.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); 
      } 
      else 
      { 
      } 

      return convertView; 
    } 

    @Override 
    public boolean isEnabled(int position) 
    { 
     return true; 
    } 

    static class ViewHolder 
    { 
      TextView instructionIndex; 
      TextView instructionText; 
      ImageView instructionImage; 
    } 
} 

카메라 UTIL :

package org.BJ.Food4All.utils; 

import java.io.File; 

import org.BJ.Food4All.DB.DBManager; 

import android.app.Activity; 
import android.content.ContentValues; 
import android.content.Intent; 
import android.database.Cursor; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.net.Uri; 
import android.os.Environment; 
import android.provider.MediaStore; 
import android.util.Log; 
//import android.widget.ImageView; 
import android.widget.Toast; 

public class CameraUtil 
{ 
    private static final String mTAG = "CameraUtil"; 

    private static final int PICK_IMAGE        = 1; 
    private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 2; 

    private Activity  mParentActivity = null; 
    private String   mFileName  = null;  // Storage filename 
// private Uri    mImageUri  = null;  // mImageUri is the current activity attribute, define and save it for later usage (also in onSaveInstanceState) 
    private Bitmap   mBitmap   = null; 
// private ImageView  mImageView  = null; 

    private DBManager  mDBManager  = null; 

    public CameraUtil(Activity parentActivity) 
    { 
     mParentActivity = parentActivity; 
     mDBManager  = new DBManager(parentActivity); 
    } 

    /** 
    * Used by the camera button - for taking a new picture 
    */ 
    public void TakePicture() 
    { 
     mFileName     = mDBManager.GetCurrentImageFilename() + ".jpg"; 
     ContentValues contentValues = new ContentValues(); 

     contentValues.put(MediaStore.Images.Media.TITLE,  mFileName); 
     contentValues.put(MediaStore.Images.Media.DESCRIPTION, "Image capture by camera"); // TODO- update description for recipe name description 

//  mImageUri = mParentActivity.getContentResolver().insert(
//       MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
//       contentValues); 

     //create new Camera Intent 
     Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 
     intent.putExtra(MediaStore.EXTRA_OUTPUT,   Uri.fromFile(getImageFile(mFileName)));//mImageUri); 
     intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); 

     try 
     { 
      mParentActivity.startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE); 
     } 
     catch(Exception e) 
     { 
      Toast.makeText(mParentActivity.getApplicationContext(), 
          "Error while starting Camera!", 
          Toast.LENGTH_LONG).show(); 

      Log.e(mTAG, "Failed to start camera"); 
      Log.e(mTAG, e.getMessage(), e); 
     } 
    } 

    /** 
    * 
    * @param requestCode 
    * @param resultCode 
    * @param data 
    */ 
    public String onActivityResult(int requestCode, int resultCode, Intent data) 
    { 
     String fileManagerString = null; 
     String selectedImagePath = null; 
     switch(requestCode) 
     { 
      case PICK_IMAGE: 
       // Used if we want to choose a picture from the gallery 
       if(resultCode == Activity.RESULT_OK) 
       { 
        Uri  selectedImageUri = data.getData(); 
        String filePath   = null; 

        try 
        { 
         // OI FILE Manager 
         fileManagerString = selectedImageUri.getPath(); 

         // MEDIA GALLERY 
         selectedImagePath = getPath(selectedImageUri); 

         if(selectedImagePath != null) 
         { 
          filePath = selectedImagePath; 
         } 
         else if(fileManagerString != null) 
         { 
          filePath = fileManagerString; 
         } 
         else 
         { 
          Toast.makeText(mParentActivity.getApplicationContext(), 
              "Unknown path", 
              Toast.LENGTH_LONG).show(); 

          Log.e(mTAG, "Unknown image path"); 
         } 

         if(filePath != null) 
         { 
          DecodeFile(filePath); 
         } 
         else 
         { 
          mBitmap = null; 
         } 
        } 
        catch(Exception e) 
        { 
         Toast.makeText(mParentActivity.getApplicationContext(), 
             "Internal error", 
             Toast.LENGTH_LONG).show(); 

         Log.e(mTAG, e.getMessage(), e); 
        } 
       } 
       break; 

      case CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE: 
       if(resultCode == Activity.RESULT_OK) 
       { 
//     Uri  selectedImageUri = mImageUri; 
        String filePath   = null; 

        try 
        { 
         // OI FILE Manager 
         fileManagerString = mFileName;//selectedImageUri.getPath(); 

         // MEDIA GALLERY 
//      selectedImagePath = mFileName;//getPath(selectedImageUri); 

         //GlobalData.setUploadedImagePath(selectedImagePath); 
    // TODO - for uploading the image 
         // Add image to the recipe images 
//      ImageUploadItem uploadItem = new ImageUploadItem(selectedImagePath); 
//      GlobalData.imageUploads.add(uploadItem); 

         // Get image path on the image 
//      if(selectedImagePath != null) 
//      { 
//       filePath = selectedImagePath; 
//      } 
//      else if(fileManagerString != null) 
//      { 
          filePath = fileManagerString; 
//      } 
//      else 
//      { 
//       
//       Toast.makeText(mParentActivity.getApplicationContext(), 
//           "Unknown path", 
//           Toast.LENGTH_LONG).show(); 
//       
//       Log.e(mTAG, "Unknown image path"); 
//      } 

         if(filePath != null) 
         { 
          String p = getImageFile(mFileName).getPath(); 
          DecodeFile(p);//filePath); 
         } 
         else 
         { 
          mBitmap = null; 
         } 
        } 
        catch(Exception e) 
        { 
         Toast.makeText(mParentActivity.getApplicationContext(), 
             "Internal error", 
             Toast.LENGTH_LONG).show(); 

         Log.e(mTAG, e.getMessage(), e); 
        } 
       } 
       break; 

      default: 
       return null; 
     } 

     // TODO Here is where the image is received from either the camera or the gallery and is in the async task 
     // TODO to go the next activity 
     return getImageFile(mFileName).getPath();//mFileName;//selectedImagePath; 
    } 

    /** 
    * 
    * @param uri 
    * @return 
    */ 
    private String getPath(Uri uri) 
    { 
     String[] projection = { MediaStore.Images.Media.DATA }; 
     Cursor  cursor  = mParentActivity.managedQuery(uri, 
                   projection, 
                   null, 
                   null, 
                   null); 
     if(cursor != null) 
     { 
      // HERE YOU WILL GET A NULLPOINTER IF CURSOR IS NULL 
      // THIS CAN BE, IF YOU USED OI FILE MANAGER FOR PICKING THE MEDIA 
      int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 

      cursor.moveToFirst(); 

      return cursor.getString(column_index); 
     } 
     else 
     { 
      return null; 
     } 
    } 

    /** 
    * 
    * @param filePath 
    */ 
    private void DecodeFile(String filePath) 
    { 
     // Decode image size 
     BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); 

     bitmapOptions.inJustDecodeBounds = true; 

     BitmapFactory.decodeFile(filePath, bitmapOptions); 

     // The new size we want to scale to 
     final int REQUIRED_SIZE = 1024; 

     // Find the correct scale value. It should be the power of 2. 
     int width_tmp = bitmapOptions.outWidth; 
     int height_tmp = bitmapOptions.outHeight; 
     int scale  = 1; 

     while(true) 
     { 
      if(width_tmp < REQUIRED_SIZE && 
       height_tmp < REQUIRED_SIZE) 
      { 
       break; 
      } 
      width_tmp /= 2; 
      height_tmp /= 2; 
      scale  *= 2; 
     } 

     // Decode with inSampleSize 
     BitmapFactory.Options newBitmapOptions = new BitmapFactory.Options(); 

     newBitmapOptions.inSampleSize = scale; 

     mBitmap = BitmapFactory.decodeFile(filePath, newBitmapOptions); 
    } 

    /** 
    * Gets the picture taken by the camera - to be used in ImageView 
    * 
    * @return 
    */ 
    public Bitmap GetTakenPictureBitmap() 
    { 
     return mBitmap; 
    } 

    /** 
    * Get the image FILE to be used for the picture taken by the camera - from filename String 
    * 
    * @param filename - the filename String 
    * @return The File representing the image file 
    */ 
    private File getImageFile(final String filename) 
    { 
      //it will return /sdcard/image.tmp 
      final File path = new File( Environment.getExternalStorageDirectory(), 
             mParentActivity.getPackageName()); 
      if(!path.exists()) 
      { 
       path.mkdir(); 
      } 

      return new File(path, filename); 
     } 
} 
+0

사용이 SO ....이 질문은 질문했다 여러 번 검색 .... – Selvin

+1

는 스택 추적을 포함하시기 바랍니다. –

답변

1

기회는 당신이 Bitmap 객체에 대한 참조에 들고, 및/또는 즉시 때를 -ing하지 recycle()되어 있습니다 그들과 함께했다. 이로 인해 99 %의 오류가 발생합니다.

0

이미지가 너무 크기 때문에 비트 맵에 직접 공간을 할당 할 수 없으므로 크기를 줄여야합니다. 비트 맵 객체를 만들기 전에 비트 맵의 ​​데이터를 가져 오지 않으면됩니다.

이 링크는 당신을 도울 것입니다 : Decoding bitmaps in Android with the right size

관련 문제