1

I want to take pictures and load them into an imageview, so that I can switch through the pictures. The picture paths are saved in a database, which is refered to my Projects. So when I load pictures into a project and reopen the project, the pictures are still visible because they are stored in the database.

My problem is, that I always run into an OutOfMemoryException with only 3 pictures. I tried to reduce the inSampleSize to a low value continusoly. But even with a inSampleSize of 15, the maximum amount of pictures can be 3.

I measured the allocated size of the bitmaps with getAllocationByteCount( ) for the different inSampleSizes:

  • 15980544 Byte = 15 MB (inSample 1) || 998784 Byte = 0.95 MB (inSample 4)
  • 249696 Byte = 0.23 MB (inSample 15)||27744 Byte = 0.02 MB (insample 30)

Because of the pictures are rotated (90° anticlockwise) I rotate them with matrix.postRotate(90) and with the matrix I create a new Bitmap. I delete the old bitmap with bitmap.recyle( ). The size of the new bitmap is 499392 Byte = 0.47 MB

First I start a Camera Intent:

// capturePicture( ) soll die Kamera starten und ein neues Bild soll gemacht werden können
private void capturePicture() {

    // erstelle einen neuen Intent, damit sich die Kamera öffnet
    // mit MediaStore.ACTION_IMAGE_CAPTURE wird angewiesen die Kamera zu starten
    CameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    // Sicherstellen, dass auf dem Handy eine Kamera installiert ist
    if (CameraIntent.resolveActivity(getPackageManager()) != null) {


        photoFile = null;


        try {
            // rufe die Methode createImageFile( ) auf, damit die Aufnahme in eine Datei gespeichert werden kann
            photoFile = createImageFile();


        } catch (IOException ex) {

            // wenn das Erstellen des Bildes fehlschlug
            Toast.makeText(thisActivity,"Bilddatei konnte nicht erstellt werden",
                    Toast.LENGTH_LONG).show();
        }

        // wenn es eine Datei gibt, soll diese in der ImageView angezeigt werden
        if (photoFile != null) {
            CameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));

            // rufe die onActivityForResult( ) Methode mit einer ID auf, um das Bild in der ImageView anzeigen zu können
            this.savePicture(photoFile.getAbsolutePath(), photoFile.getName());
            startActivityForResult(CameraIntent, REQUEST_TAKE_PHOTO);
            //bitmap.recycle();
            //System.gc();
            this.reloadPicDB();
        }


    } else {

        // TODO: auf den Play Store mit einer Kamera App verweisen
        Toast.makeText(thisActivity,"Sie haben leider keine Kamera installiert", Toast.LENGTH_SHORT).show();
    }

    photoCount++;

}

In this method I call the method createImageFile( ) in order to create an Imagefile:

    // erstellt eine Datei nachdem ein Foto gemacht wurde und gibt diese zurück
    private File createImageFile() throws IOException {

        // TODO: Sinnvollen Dateinamen für die Bilddateien geben
        //String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmmss").format(new Date());

        imageFileName = "JPEGNEU";

        // TODO: überlegen, wohin die Bilddateien gespeichert werden sollen
        //File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        File pictureStorageDir = new File("/sdcard/neu/");

        // In der Datei pictureImage werden der Name, Endung und Verzeichnis gespeichert        
        File pictureImage = File.createTempFile(imageFileName, /* prefix */
                ".jpg", /* suffix */
                pictureStorageDir /* directory */
        );

        // ermittle den absoluten Pfad der Bilddatei und speichere diesen in den String PhotoPath
        PhotoPath = pictureImage.getAbsolutePath();

        // gebe die Bilddatei zurück, damit dieses in der Methode capturePicture weiter verwendet werden kann
        return pictureImage;

    }

The picture will be shown in the onActivityResult( ) method:

    if(requestCode == REQUEST_TAKE_PHOTO){


            ImageView beispiel = (ImageView) findViewById(R.id.beispiel);
BitmapFactory.Options options1 = new BitmapFactory.Options();
            options1.inSampleSize = 15;     //1/12 des Bildes zu laden

options1.inPreferredConfig = Config.ARGB_4444; 
            Bitmap image = BitmapFactory.decodeFile(PhotoPath, options1);
            Log.d("Speicherausgabe", "Speicherausgabe0.1 " + image.getAllocationByteCount());
Matrix matrix = new Matrix();
            matrix.postRotate(90);

            bitmap = Bitmap.createBitmap(image, 0, 0, image.getWidth() , image.getHeight(), matrix, true);
image.recycle();
            System.gc();

if(zaehlerRequestPhoto == 0){
beispiel.setImageBitmap(bitmap);
} else {
                beispiel.setImageBitmap(bitmap);
                Log.d("Speicherausgabe", "Speicherausgabe3 " + bitmap.getAllocationByteCount());
                //System.gc();




            }

What shall I do to avoid the OutOfMemoryException in this case?

Vik0809
  • 379
  • 4
  • 18

3 Answers3

1

The out of memory exception occurs often when your application resources exceeds the available heap memory. Particularly the bitmap utilizes more memory and its cache not cleared until the maximum memory reached and Garbage Collector do its works. So that please use LruCache to avoid the out of memory exception or simply use the library Universal Image Loader available from here. https://github.com/nostra13/Android-Universal-Image-Loader

Rajkumar Nagarajan
  • 1,091
  • 1
  • 10
  • 6
1

Once you are ready with your image, you should recycle and null it like below:

image.recycle();
image=null;

OR

You can also increase the heap space by adding to your AndroidManifest:

<application 
     android:label="@string/app_name"
     android:largeHeap="true"
     ...
Robin
  • 709
  • 2
  • 8
  • 20
0

I have asked this question before Here

But i was still not able to solve the issue completely, but was able to reduce the intensity with the below code thanks to @Binh Tran

public Bitmap decodeSampledBitmapFromResourceMemOpt(
            InputStream inputStream, int reqWidth, int reqHeight) {

        byte[] byteArr = new byte[0];
        byte[] buffer = new byte[1024];
        int len;
        int count = 0;

        try {
            while ((len = inputStream.read(buffer)) > -1) {
                if (len != 0) {
                    if (count + len > byteArr.length) {
                        byte[] newbuf = new byte[(count + len) * 2];
                        System.arraycopy(byteArr, 0, newbuf, 0, count);
                        byteArr = newbuf;
                    }

                    System.arraycopy(buffer, 0, byteArr, count, len);
                    count += len;
                }
            }

            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeByteArray(byteArr, 0, count, options);

            options.inSampleSize = calculateInSampleSize(options, reqWidth,
                    reqHeight);
            options.inPurgeable = true;
            options.inInputShareable = true;
            options.inJustDecodeBounds = false;
            options.inPreferredConfig = Bitmap.Config.ARGB_8888;

            int[] pids = { android.os.Process.myPid() };
            MemoryInfo myMemInfo = mAM.getProcessMemoryInfo(pids)[0];
            Log.e(TAG, "dalvikPss (decoding) = " + myMemInfo.dalvikPss);

            return BitmapFactory.decodeByteArray(byteArr, 0, count, options);

        } catch (Exception e) {
            e.printStackTrace();

            return null;
        }
    }
The method that does the calculation:

public void onButtonClicked(View v) {
        int[] pids = { android.os.Process.myPid() };
        MemoryInfo myMemInfo = mAM.getProcessMemoryInfo(pids)[0];
        Log.e(TAG, "dalvikPss (beginning) = " + myMemInfo.dalvikPss);

        long startTime = System.currentTimeMillis();

        FileInputStream inputStream;
        String filePath = Environment.getExternalStorageDirectory()
                .getAbsolutePath() + "/test2.png";
        File file = new File(filePath);
        try {
            inputStream = new FileInputStream(file);
//          mBitmap = decodeSampledBitmapFromResource(inputStream, 800, 800);
            mBitmap = decodeSampledBitmapFromResourceMemOpt(inputStream, 800,
                    800);
            ImageView imageView = (ImageView) findViewById(R.id.image);
            imageView.setImageBitmap(mBitmap);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        myMemInfo = mAM.getProcessMemoryInfo(pids)[0];
        Log.e(TAG, "dalvikPss (after all) = " + myMemInfo.dalvikPss
                + " time = " + (System.currentTimeMillis() - startTime));
    }
Community
  • 1
  • 1
Goofy
  • 6,098
  • 17
  • 90
  • 156