Harin Kaklotar
Harin Kaklotar

Reputation: 325

java.lang.OutOfMemoryError when createBitmap

Hi i am creating image editing app wher i am create bitmap for canvas and imageview

here i am using 385kb image file with 2000x2000 dimension in imageView

here is the imageenter image description here

my problem is that first time i create bitmap with other small image and edit image it work some time but for second time with above size and dimension it generate java.lang.OutOfMemoryError :(

this is my related methods code

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

        // initialize variable
        init();

        // initialize view
        initView();

        // initialize view's event listener
        initEventListener();

        setImageToImageView(ims);

    }  

private void init() {

        context = MainActivity.this;
        db_colorImage = new DB_ColorImage(context);

        AppUtils.setColorPreference(MainActivity.this, AppConstant.PREF_COLOR_PIC, "FF0000");
        AppUtils.setComboColorPreference(MainActivity.this, AppConstant.PREF_COMBO, 1);

        openCatId = getIntent().getIntExtra("open_cat_id", -1);
        openCat = getIntent().getStringExtra("image_categoryname");
        openImgName = getIntent().getStringExtra("img_name");

        db_colorImage.openDB();
        db_colorImage.startTransaction();
        assetsImgxx = db_colorImage.getXXX(openCatId);
        db_colorImage.successfullTransaction();
        db_colorImage.completeTransaction();
        db_colorImage.closeDB();


        assetsAndSdImage = new ArrayList<>(getIntent().getStringArrayListExtra("again"));           // aa list edit karelu with sdcard image

        try {

            ims = getAssets().open(openCat + "/" + openImgName);
        } catch (IOException e) {
            File getFromSd = new File(AppUtils.appFolder() + File.separator + openImgName);
            try {
                ims = new FileInputStream(getFromSd);
            } catch (FileNotFoundException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }

    }  

    public void setImageToImageView(InputStream ims) {
        Drawable d = Drawable.createFromStream(ims, null);

        BitmapDrawable drawable = (BitmapDrawable) d;

        Bitmap bmp = drawable.getBitmap();


        if (bmp != null) {
            _alteredBitmap = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888); // here i used ARGB_8888 because jnibitmap.cpp also use ARGB_8888. If we do not use this it wont color on image
        }

        Canvas canvas = new Canvas(_alteredBitmap);

        Paint paint = new Paint();

        Matrix matrix = new Matrix();

        canvas.drawBitmap(bmp, matrix, paint);

        imageView.setImageBitmap(_alteredBitmap);  // we can also use imageView.setImageResource(R.drawable.test_image);

        // ******* clear bitmap after use *******
        // check after done this step it will not produce any problem
        if (bmp != null) {
            bmp.recycle();
            bmp = null;
        }
    }  

_alteredBitmap = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888);

at this line where i get EXCEPTION, here is the log

01-27 19:12:33.590 27252-27252/? E/AndroidRuntime: FATAL EXCEPTION: main
                                                   java.lang.OutOfMemoryError
                                                       at android.graphics.Bitmap.nativeCreate(Native Method)
                                                       at android.graphics.Bitmap.createBitmap(Bitmap.java:640)
                                                       at android.graphics.Bitmap.createBitmap(Bitmap.java:620)
                                                       at com.yptech.myfloodfilldemo.ui.MainActivity.setImageToImageView(MainActivity.java:387)
                                                       at com.yptech.myfloodfilldemo.ui.MainActivity.onCreate(MainActivity.java:96)
                                                       at android.app.Activity.performCreate(Activity.java:5008)
                                                       at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
                                                       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
                                                       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
                                                       at android.app.ActivityThread.access$600(ActivityThread.java:130)
                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
                                                       at android.os.Handler.dispatchMessage(Handler.java:99)
                                                       at android.os.Looper.loop(Looper.java:137)
                                                       at android.app.ActivityThread.main(ActivityThread.java:4745)
                                                       at java.lang.reflect.Method.invokeNative(Native Method)
                                                       at java.lang.reflect.Method.invoke(Method.java:511)
                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
                                                       at dalvik.system.NativeStart.main(Native Method)  

After edit image I am saving this image so I don't want to reduce image quality so I use Bitmap.Config.ARGB_8888. I tried so many solution like android developer document on bitmap but it not work for me.

is OutOfMemoryError depends upon image size and dimension ??? and how to solve my problem for OutOfMemoryError while createBitmap ??

when I am using largHeap it work fine but is that better approach to use android:largeHeap="true" ??

thanks in advance :)

Upvotes: 4

Views: 5213

Answers (4)

D.Roters
D.Roters

Reputation: 231

I'm using Glide (https://bumptech.github.io/glide/) to loading large bitmaps efficiently. In case of loading photos from your device Glide also handle the correct rotation for you.

val myUri = ...
val neededHeight = 600
val neededWidth = 800

val bitmap = GlideApp
                .with(context)
                .asBitmap()
                .load(myUri)
                .override(neededWidth, neededHeight)
                .submit()
                .get()

Upvotes: 1

Jaydev
Jaydev

Reputation: 1812

Optimize the bitmap before using it.

Bitmap bitmap = MediaOptimize.reduceResolution(mediaPath, width, height);

Functions:

public Bitmap reduceResolution(String filePath, int viewWidth, int viewHeight) {
    int reqHeight = viewHeight;
    int reqWidth = viewWidth;

    BitmapFactory.Options options = new BitmapFactory.Options();

    // First decode with inJustDecodeBounds=true to check dimensions
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(filePath, options);

    double viewAspectRatio = 1.0 * viewWidth/viewHeight;
    double bitmapAspectRatio = 1.0 * options.outWidth/options.outHeight;

    if (bitmapAspectRatio > viewAspectRatio)
        reqHeight = (int) (viewWidth/bitmapAspectRatio);
    else
        reqWidth = (int) (viewHeight * bitmapAspectRatio);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    System.gc();                                        // TODO - remove explicit gc calls
    return BitmapFactory.decodeFile(filePath, options);
}


private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {

    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }
    return inSampleSize;
}

Upvotes: 2

Bram Jongebloet
Bram Jongebloet

Reputation: 336

The image is way to big. I recommend shrinking the image or using picasso library to make better use of memory issues and image caching.

Upvotes: -1

Simon
Simon

Reputation: 1190

Try this out, just add it to AndroidManifest.xml

<application
    ...
    android:largeHeap="true">
    <activity
        android:name=".MainActivity"
        ...

Upvotes: -1

Related Questions