Утечка памяти в Android при попытке отправить форму с изображением на сервер PHP


1 Answers

Растровые изображения используют много памяти. Для эффективного использования растровых изображений вам необходимо позаботиться о следующем:

  • Помните, что ваши png в drawables автоматически изменяются по размеру экрана с помощью android. И это занимает много памяти. Android не изменяет размер изображений, если он находит изображения требуемого размера / масштаба в правильной папке с возможностью рисования. Поэтому, чтобы начать с копирования всех файлов ldpi в hdpi. Это уменьшит использование памяти на 40%. Я знаю, как это звучит, но это правда, профилируйте свое приложение, используя debuggable = true в манифесте, и использование кучи с использованием ddms. Внесите изменения и выполните точно такой же сценарий, вы заметите снижение на 40%.
  • Когда вы читаете растровое изображение, уменьшите его. Не используйте только CreateBitmap , так как он будет читать весь файл и использовать намного больше памяти. Вместо этого используйте BitmapOptions и уменьшите его. Чтобы уменьшить масштаб, сначала нужно установить свои параметры, а затем использовать эти параметры в качестве параметра для вашего вызова CreateBitmap . Вот хорошая ссылка. Подробнее о stackoverflow вы найдете еще несколько интересных ответов.
  • Если в ваших чертежах есть файлы размером 1024X512, уменьшите их. ИЛИ Создайте новые файлы, которые являются ясными, но меньшими по размеру. Используйте эти файлы для mdpi, удалите ldpi. Используйте 1024X512 для своей папки hdpi.
  • Исследуйте возможность использования меньших файлов, сортируйте по размеру и немного поиграйте с ним. Графический вид eclipse для xml-файлов действительно опрятен и относительно свободен от ошибок. Используй это.
  • Отредактировано: Не забудьте удалить свой растровый рисунок для сбора мусора. Это самое важное.
Question

У меня есть утечка памяти в этом файле, я не могу найти, где именно, но я думаю, что изображение вокруг -> (Bitmap bm = BitmapFactory.decodeFile(filename)) , я пробовал много разных способов, но я не могу получить его работать.

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;
}

}

Журнал ошибок

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



Не могу сказать наверняка, так как я не разработчик Java, но в .NET. BitMap calss IDisposable и рекомендуется перерабатывать, как только он не используется.
Может быть, вы должны освободить свою память после загрузки BitMap?






Related