title: Memory leak in Android when trying to send a form with image to PHP server
body: <p>I have a memory leak in this file, I cannot find where exactly, but I think is the image around --> <code>(Bitmap bm = BitmapFactory.decodeFile(filename))</code>, I have tried many different ways but I can't get it to work.</p>
  
  <pre><code>package prod.vegs;
  
  //All imports here but not need to write them all now :-)
  
  
  public class ProductForm extends Activity {
  
  private static int TAKE_PICTURE = 1;
  private static int SELECT_PICTURE = 2;
  
  //JSON Response node names
  private static String KEY_SUCCESS = "success";
  private static String ERROR_MSG = "error_msg";
  private static String KEY_TYPES = "subtypes";
  private static String TYPE_NAME = "name";
  private static String TYPE_ID = "id_type";
  private static String PRODUCT_ID = "id_product";
  
  private JSONObject json;
  private JSONParser jsonParser;
  private String barcodeStr;
  private String filename;
  private int code;
  private ProgressDialog dialog;
  private TypeClass[] items;
  private TypeClass[] sub_items;
  
  //Declare assets objects
  Spinner type;
  Spinner subtype;
  TextView errorMsg;
  TextView description;
  TextView name;
  Button camera;
  Button gallery;
  Intent intent;
  ImageView preview;
  Bundle bundle;
  LinearLayout errorMsgContainer;
  
  Context context;
  
  public void onCreate(Bundle icicle) {
      super.onCreate(icicle);
      setContentView(R.layout.product_form);
      context = this;
  
      Bundle b = getIntent().getExtras();
      barcodeStr = b.getString("barcode");
  
      jsonParser = new JSONParser();
      dialog = new ProgressDialog(this);
      dialog.setMessage(getString(R.string.loading));
      dialog.setTitle(getString(R.string.progress));
      dialog.setCancelable(true);
  
      //Set assets
      name = (TextView) findViewById(R.id.productName);
      description = (TextView) findViewById(R.id.productDescription);
      errorMsg = (TextView) findViewById(R.id.error_msg);
      errorMsgContainer = (LinearLayout) findViewById(R.id.error_msg_container);
      type = (Spinner) findViewById(R.id.productParentType);
      subtype = (Spinner) findViewById(R.id.productType);
      camera = (Button) findViewById(R.id.productCamera);
      gallery = (Button) findViewById(R.id.productGallery);
      preview = (ImageView) findViewById(R.id.productPreview);
      filename = Environment.getExternalStorageDirectory() + String.format(getString(R.string.api_product_form_picture_file), barcodeStr);
  
      Boolean fromScanner = b.getBoolean("scanner");
      if (fromScanner == true) {
  
          AlertDialog.Builder alertbox = new AlertDialog.Builder(this);
          alertbox.setMessage(getString(R.string.insert_product));
          alertbox.setPositiveButton(getString(R.string.yes), 
              new DialogInterface.OnClickListener() {
                  public void onClick(DialogInterface arg_1, int arg_num) {
                      final Functions function = new Functions();
                      List&lt;NameValuePair&gt; params = new ArrayList&lt;NameValuePair&gt;();
                      String url = String.format(getString(R.string.api_product_form_types_url), getString(R.string.api_url));
                      json = function.loadJSONUrl(url, params);
                      if(json != null){
                          try {
                              if (json.getString(KEY_SUCCESS) != null) {
                                  String res = json.getString(KEY_SUCCESS);
                                  if(Integer.parseInt(res) == 1){
  
                                      JSONArray types = json.getJSONArray(KEY_TYPES);
                                      items = convertJSONArray(types);
  
                                      SpinAdapter listViewArrayAdapter = new SpinAdapter(context, android.R.layout.simple_spinner_item, items);
                                      listViewArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                                      type.setAdapter(listViewArrayAdapter);
                                      type.setOnItemSelectedListener(new OnItemSelectedListener(){
                                          public void onItemSelected(AdapterView&lt;?&gt; parent, View v, int pos, long id) {
                                              try {
                                                  String url = String.format(getString(R.string.api_subtypes_id_url), getString(R.string.api_url), ((TypeClass) type.getSelectedItem()).getId());
                                                  List&lt;NameValuePair&gt; params = new ArrayList&lt;NameValuePair&gt;();
                                                  JSONObject json_subtypes = function.loadJSONUrl(url, params);
                                                  if (json_subtypes.getString(KEY_SUCCESS) != null) {
                                                      JSONArray subtypes = json_subtypes.getJSONArray(KEY_TYPES);
                                                      sub_items = convertJSONArray(subtypes);
                                                      SpinAdapter subTypeAdapter = new SpinAdapter(context, android.R.layout.simple_spinner_item, sub_items);
                                                      subTypeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                                                      subtype.setAdapter(subTypeAdapter);
                                                      subtype.setPrompt("Selecciona la cateogría");
                                                  }
                                              } catch (Exception e) {
                                                  e.printStackTrace();
                                              }
                                          }
  
                                          public void onNothingSelected(AdapterView&lt;?&gt; args) {
                                              //Auto-generated method stub
                                          }
                                      });
                                      type.setPrompt("Selecciona la cateogría");
  
                                      //camera action
                                      camera.setOnClickListener(new View.OnClickListener() {
                                          public void onClick(View view) {
                                              intent =  new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                                              int timeMili = (int) (System.currentTimeMillis());
                                              filename = Environment.getExternalStorageDirectory() + "/" + timeMili + ".jpg";
                                              Uri output = Uri.fromFile(new File(filename));
                                              intent.putExtra(MediaStore.EXTRA_OUTPUT, output);
                                              code = TAKE_PICTURE;
                                              startActivityForResult(intent, code);   
                                          }
                                      });
  
                                      //gallery action
                                      gallery.setOnClickListener(new View.OnClickListener() {
                                          public void onClick(View view) {
                                              intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI);
                                              code = SELECT_PICTURE;
                                              startActivityForResult(intent, code);
                                          }
                                      });
  
                                      //button of the form
                                      Button button = (Button) findViewById(R.id.button);
                                      button.setOnClickListener(new View.OnClickListener() {
                                          public void onClick(View view) {
                                              if (!NetworkHelper.CheckNetworkStatus(view.getContext())) {
                                                  return;
                                              }
                                              bundle = new Bundle();
                                              bundle.putString("barcode", barcodeStr.toString());
                                              bundle.putString("name", name.getText().toString());
                                              bundle.putString("description", description.getText().toString());
                                              bundle.putString("type_id", ((TypeClass) subtype.getSelectedItem()).getId());
  
                                              if (_checkFormValues()) {
                                                  new SendDataJSON().execute(view);
                                              } else {
                                                  Toast.makeText( view.getContext(), getString(R.string.error_form_incomplete), Toast.LENGTH_LONG).show();
                                              }
                                          }
                                      });
  
                                  }  else {
                                      errorMsg.setText(json.getString(ERROR_MSG));
                                      errorMsgContainer.setVisibility(LinearLayout.VISIBLE);
                                  }
                              }
                          } catch (JSONException e) {
                              e.printStackTrace();
                          }
                      } else {
  
                      }
                  }
          }).setNegativeButton("No", 
              new DialogInterface.OnClickListener() {
                  public void onClick(DialogInterface arg0, int arg1) {
                      Intent myIntent = new Intent(ProductForm.this, CaptureActivity.class);
                      startActivity(myIntent);
                      finish();
                  }
          }).show();
  
      } else {
          finish();
      }  
  
  }
  
  class SendDataJSON extends AsyncTask&lt;View, Void, View&gt;{
  
      @Override
      protected View doInBackground(View... views) {
  
          String url = String.format(getString(R.string.api_product_form_url),getString(R.string.api_url)); 
          HttpPost httpPost = new HttpPost(url);
  
          try {
              // Add your data
              MultipartEntity entity = new MultipartEntity();
  
              File photo = new File(filename);
              if (photo.exists()) {
                  //create the compressed image to send                   
                  //create the file to send the image
                  File sd = Environment.getExternalStorageDirectory();
                  File data = Environment.getDataDirectory();
                  if (!sd.canWrite()) { sd = data; }
                  String destinationFolderPath = sd + "/" + getString(R.string.app_dir) + "/";
                  String destinationImageName= "photo_" + bundle.getString("barcode") + ".jpg";
  
                  //create the folder to store it
                  File destinationFolder = new File(destinationFolderPath);
                  if (!destinationFolder.exists()) {
                      destinationFolder.mkdirs();
                  }
  
                  File destination = new File(destinationFolder, destinationImageName);
                  FileOutputStream out = new FileOutputStream(destination);
  
                  Bitmap bm = BitmapFactory.decodeFile(filename);                 
                  int width = bm.getWidth();
                  int height = bm.getHeight();
                  int max_value = 1024;
                  int max = Math.max(width,height);
                  if (max &gt; max_value) {
                      width = width * max_value / max;
                      height = height * max_value / max;
                  }
  
                  //Make the new image with the new size values
                  try {
                      Bitmap bm2 = Bitmap.createScaledBitmap(bm, width, height, true);
                      //Compress the image
                      bm2.compress(CompressFormat.JPEG, 75, out);                     
                      out.flush();
                      out.close();                        
                      destination = new File(destinationFolder, destinationImageName);                        
                      FileBody filePhoto = new FileBody(destination);
                      entity.addPart("image", filePhoto);
                  } catch (Exception e) {
                      Log.w(ProductForm.class.getSimpleName(), e);
                  }
  
              }
              SharedPreferences userSettings = getSharedPreferences("UserPreferences", Context.MODE_PRIVATE); 
              Charset chars = Charset.forName("UTF-8");
              entity.addPart("barcode", new StringBody(bundle.getString("barcode"),chars));
              entity.addPart("name", new StringBody(bundle.getString("name"),chars));
              entity.addPart("description", new StringBody(bundle.getString("description"),chars));
              entity.addPart("id_type", new StringBody(bundle.getString("type_id")));
              entity.addPart("uid",new StringBody(userSettings.getString("uid", ""),chars));
              httpPost.setEntity(entity);
              HttpClient httpclient = new DefaultHttpClient();
              httpclient.execute(httpPost);
  
          } catch (IOException e) {
              //
          }
  
          return views[0];
      }
  
      @Override
      protected void onPreExecute() {
          dialog.setMax(100);
          dialog.setProgress(0);
          dialog.show();
      }
  
      @Override
      protected void onPostExecute(View view) {
          //redirect to the product page          
          setContentView(R.layout.product_barcode);           
          String url = String.format(getString(R.string.api_product_barcode_url), getString(R.string.api_url), bundle.getString("barcode"));  
          new LoadJSONBarcode().execute(url);
      }
  }
  
  //Send data to server and receive respond
  private class LoadJSONBarcode extends AsyncTask&lt;String, Void, JSONObject&gt;{
  
      @Override
      protected JSONObject doInBackground(String... urls) {
          List&lt;NameValuePair&gt; params = new ArrayList&lt;NameValuePair&gt;();
          json = new JSONObject();
          json = jsonParser.getJSONFromUrl(urls[0], params);
          return json;
      }
  
      @Override
      protected void onPreExecute() {
          dialog.setMax(100);
          dialog.setProgress(0);
          dialog.show();
      }
  
      @Override
      protected void onPostExecute(JSONObject json) {
  
          if (json != null) {
              try {
  
                  if (json.getString(KEY_SUCCESS) != null) {
                      String res = json.getString(KEY_SUCCESS);
                      if(Integer.parseInt(res) == 1){
                          View view = findViewById(R.id.productBarcodeXML);                       
                          Intent myIntent = new Intent(view.getContext(), Product.class);
                          Bundle b = new Bundle();
                          b.putString("id", json.getString(PRODUCT_ID));
                          myIntent.putExtras(b);
                          view.getContext().startActivity(myIntent);
                      } else {
                          errorMsg.setText(json.getString(ERROR_MSG));
                          errorMsgContainer.setVisibility(LinearLayout.VISIBLE);
                      }
                      dialog.dismiss();
                  }
  
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
  
  }
  
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      if (requestCode == TAKE_PICTURE) {
          if (data != null) {
              if (data.hasExtra("data")) { 
                  preview.setImageBitmap((Bitmap) data.getParcelableExtra("data"));
                  preview.setVisibility(ImageView.VISIBLE);
              }
          } else {
              preview.setImageBitmap(BitmapFactory.decodeFile(filename));
              preview.setVisibility(ImageView.VISIBLE);
              new MediaScannerConnectionClient() {
                  private MediaScannerConnection msc = null; {
                      msc = new MediaScannerConnection(getApplicationContext(), this); msc.connect();
                  }
                  public void onMediaScannerConnected() { 
                      msc.scanFile(filename, null);
                  }
                  public void onScanCompleted(String path, Uri uri) { 
                      msc.disconnect();
                  } 
              };              
          }
      } else if (requestCode == SELECT_PICTURE){
          if (data != null){ 
              Uri selectedImage = data.getData();
              InputStream is;
              String[] filePathColumn = {MediaStore.Images.Media.DATA};
              Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
              cursor.moveToFirst();
  
              int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
              filename = cursor.getString(columnIndex);
              cursor.close();
  
              try {
                  is = getContentResolver().openInputStream(selectedImage);
                  BufferedInputStream bis = new BufferedInputStream(is);
                  Bitmap bitmap = BitmapFactory.decodeStream(bis);            
                  preview.setImageBitmap(bitmap);     
                  preview.setVisibility(ImageView.VISIBLE);
              } catch (FileNotFoundException e) {
  
              }
          }
      } 
  }
  
  private TypeClass[] convertJSONArray(JSONArray jsonArray){
      int len = jsonArray.length();
      TypeClass[] t = new TypeClass[len];
      if (jsonArray != null) { 
          for (int i=0;i&lt;len;i++){ 
              try {
                  JSONObject o = jsonArray.getJSONObject(i);
                  t[i] = new TypeClass();
                  t[i].setName(o.getString(TYPE_NAME));
                  t[i].setId(o.getString(TYPE_ID));
              } catch (JSONException e) {
                  e.printStackTrace();
              }
         } 
      } 
      return t;
  }
  
  protected boolean _checkFormValues() {
  
      boolean result = true;
  
      if (name.getText().length() == 0) {
          name.requestFocus();
          result = false;
      }
      if (((TypeClass) subtype.getSelectedItem()).getId() == null){
          subtype.requestFocus();
          result = false;
      }
      return result;
  }
  
  }
  </code></pre>
  
  <p>Error Log</p>
  
  <pre><code>11-07 23:55:26.914: E/AndroidRuntime(15457): FATAL EXCEPTION: AsyncTask #3
  11-07 23:55:26.914: E/AndroidRuntime(15457): java.lang.RuntimeException: An error occured while executing doInBackground()
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at android.os.AsyncTask$3.done(AsyncTask.java:278)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at java.util.concurrent.FutureTask.run(FutureTask.java:137)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at java.lang.Thread.run(Thread.java:864)
  11-07 23:55:26.914: E/AndroidRuntime(15457): Caused by: java.lang.OutOfMemoryError: (Heap Size=35491KB, Allocated=27993KB)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at android.graphics.BitmapFactory.nativeDecodeFile(Native Method)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:373)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:443)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at prod.vegs.ProductForm$SendDataJSON.doInBackground(ProductForm.java:272)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at prod.vegs.ProductForm$SendDataJSON.doInBackground(ProductForm.java:1)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at android.os.AsyncTask$2.call(AsyncTask.java:264)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
  11-07 23:55:26.914: E/AndroidRuntime(15457):    ... 4 more
  </code></pre>