Android memory leak when trying to submit form with image to PHP server

I have a memory leak in this file, I can not find where exactly, but I think the image is around → (Bitmap bm = BitmapFactory.decodeFile(filename)) , I tried many different ways, but I can not get it to work .

 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<NameValuePair> params = new ArrayList<NameValuePair>(); 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<?> 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<NameValuePair> params = new ArrayList<NameValuePair>(); 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<?> 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<View, Void, View>{ @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 > 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<String, Void, JSONObject>{ @Override protected JSONObject doInBackground(String... urls) { List<NameValuePair> params = new ArrayList<NameValuePair>(); 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<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; } } 

Error log

 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 
+8
android memory-leaks android-asynctask bitmap
source share
5 answers

Raster images are very large memory consumers. Having two loaded into memory can be a big problem. You should use BitmapFactory.Options when decoding a new bitmap. In addition, you do not need bm2 . Instead, replace this line as follows:

 bm = Bitmap.createScaledBitmap(bm, width, height, true); 

Finally, if you have no other options, you can increase the heap size of the application using the Application android:largeHeap="true" attribute in your AndroidManifest.xml. This option is not required - and should only be considered for applications with an extremely intensive graphical interface.

EDIT

Another link that may be useful for optimizing the use of Bitmap: http://developer.android.com/training/tv/optimizing-layouts-tv.html#HandleLargeBitmaps

+10
source share

Raster images use a lot of memory. You need to make sure that you use raster images effectively.

  • Remember that your png in drawables is automatically resized to screen size using android. And it takes a lot of memory. Android does not resize images if it finds images of the required size / scale in the right drawable folder. Therefore, to start by copying all ldpi files to hdpi. This will reduce memory usage by 40%. I know how that sounds, but it's true, profile your application using debuggable = true in the manifest, and using heap using ddms. Make changes and follow exactly the same scenario, you will notice a decrease of 40%.
  • When you read a bitmap, reduce it. Do not use only CreateBitmap , as it will read the entire file and use a lot more memory. Use BitmapOptions and zoom out. To zoom out, you first need to set your parameters, and then use these parameters as a parameter for your CreateBitmap call. Here is a good link. For more on stackoverflow, you will find more interesting answers.
  • If you have files in your drawings 1024X512, reduce them. OR Create new files that are clear, but smaller in size. Use these files for mdpi, delete ldpi. Use 1024X512 for your hdpi folder.
  • Explore the possibility of using smaller files, sort by size and play a little with it. The graphical view of eclipse for xml files is really neat and relatively error free. Use it.
  • Edited: Remember to delete your bitmap for garbage collection. This is the most important.
+4
source share

A few general tips:

  • As @Phil suggested, Bitmap objects tend to eat a lot of memory in Android. You should always use SoftReferences to store bitmaps so that the OS can free memory if necessary.
  • You should also use the recycle() method to bm2 transform bitmaps (i.e. your bm2 variable) when you are done with them.
  • As paranoid as it sounds, setting bitmaps to NULL when you are done with them is a good practice to hint to the garbage collector that they can be collected. However, as a rule, manually calling gc in Android will either aggravate the situation or have no effect.
  • And finally, the profile of your application using ddms !
+2
source share

I can’t say for sure, since I'm not a Java developer, but in .NET BitMap calss is IDisposable and it is recommended to recycle as soon as it is not used.
Maybe you should free your memory after downloading BitMap?

0
source share

Yes A memory cache provides quick access to bitmaps through the use of valuable application memory. If LruCache cannot solve the problem, you can try the following: ImageManager , in the ImageManager class it has the recycleBitmaps method.

0
source share

All Articles