Out of memory on a 16571536 byte allocation

12,534

You are running out of memory because you are not handling images carefully. Take a look at following question/answer for a better idea what happens when you try to load an image: Strange out of memory issue while loading an image to a Bitmap object

If you are a new developer then I would recommend you to just use any good library that does loading part for you otherwise it would be very hard to load images.

Android-Universal-Image-Loader: Widely used library https://github.com/nostra13/Android-Universal-Image-Loader

Alternative Picasso Library: One line of code does the job for you: http://square.github.io/picasso/

Updated:

Bitmaps take up a lot of memory, especially for rich images like photographs. For example, the camera on the Galaxy Nexus takes photos up to 2592x1936 pixels (5 megapixels). If the bitmap configuration used is ARGB_8888 (the default from the Android 2.3 onward) then loading this image into memory takes about 19MB of memory (2592*1936*4 bytes), immediately exhausting the per-app limit on some devices.

http://developer.android.com/training/displaying-bitmaps/index.html

Share:
12,534
cphelps76
Author by

cphelps76

Updated on June 05, 2022

Comments

  • cphelps76
    cphelps76 almost 2 years

    Basically i'm adding a wallpaper picker for android 4.4.2 lockscreen background and when the image is set and i turn the screen off then back on to view the lockscreen my screen is going black and logcat is giving me an out of memory allocation error. So far i have tried using Bitmap decodeFile(String pathName) and i also rebased to use Bitmap decodeFile(String pathName, Options opts) but the result is the same every time...

    Here is the original method used to set the image:

    private static final String WALLPAPER_IMAGE_PATH =
            "/data/data/com.android.settings/files/lockscreen_wallpaper.png";
    
    private KeyguardUpdateMonitorCallback mBackgroundChanger = new KeyguardUpdateMonitorCallback() {
        @Override
        public void onSetBackground(Bitmap bmp) {
            if (bmp != null) {
                mKeyguardHost.setCustomBackground(
                        new BitmapDrawable(mContext.getResources(), bmp));
            }
            else {
                File file = new File(WALLPAPER_IMAGE_PATH);
                if (file.exists()) {
                    mKeyguardHost.setCustomBackground(
                            new BitmapDrawable(mContext.getResources(), WALLPAPER_IMAGE_PATH));
                }
                else {
                    mKeyguardHost.setCustomBackground(null);
                }
            }
            updateShowWallpaper(bmp == null);
        }
    };
    

    which is being called from case 1 in:

        public void setCustomBackground(Drawable d) {
            if (!mAudioManager.isMusicActive()) { 
    
                int mBackgroundStyle = Settings.System.getInt(mContext.getContentResolver(),
                        Settings.System.LOCKSCREEN_BACKGROUND_STYLE, 2);
                int mBackgroundColor = Settings.System.getInt(mContext.getContentResolver(),
                        Settings.System.LOCKSCREEN_BACKGROUND_COLOR, 0x00000000);
                switch (mBackgroundStyle) {
                    case 0:
                        d = new ColorDrawable(mBackgroundColor);
                        d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER);
                        mCustomBackground = d;
                        break;
                    case 1:
                        KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground(null);
                        break;
                    case 2:
                    default:
                        mCustomBackground = d;
                }
                computeCustomBackgroundBounds(mCustomBackground);
                setBackground(mBackgroundDrawable);
            }
    
            if (!ActivityManager.isHighEndGfx()) {
                mCustomBackground = d;
                if (d != null) {
                    d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER);
                }
                computeCustomBackgroundBounds(mCustomBackground);
                invalidate();
            } else {
                if (getWidth() == 0 || getHeight() == 0) {
                    d = null;
                }
                if (d == null) {
                    mCustomBackground = null;
                    setBackground(mBackgroundDrawable);
                    return;
                }
                Drawable old = mCustomBackground;
                if (old == null) {
                    old = new ColorDrawable(0);
                    computeCustomBackgroundBounds(old);
                }
    
                d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER);
                mCustomBackground = d;
                computeCustomBackgroundBounds(d);
                Bitmap b = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
                Canvas c = new Canvas(b);
                mBackgroundDrawable.draw(c);
    
                Drawable dd = new BitmapDrawable(b);
    
                mTransitionBackground = new TransitionDrawable(new Drawable[]{old, dd});
                mTransitionBackground.setCrossFadeEnabled(true);
                setBackground(mTransitionBackground);
    
                mTransitionBackground.startTransition(200);
    
                mCustomBackground = dd;
                invalidate();
            }
    
            if (d != null) {
                d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER);
            }
            computeCustomBackgroundBounds(mCustomBackground);
            invalidate();
        }
    

    this is my logcat output:

    I/dalvikvm-heap(13100): Forcing collection of SoftReferences for 16571536-byte allocation
    E/dalvikvm-heap(13100): Out of memory on a 16571536-byte allocation.
    I/dalvikvm(13100): "main" prio=5 tid=1 RUNNABLE
    I/dalvikvm(13100):   | group="main" sCount=0 dsCount=0 obj=0x4159fe40 self=0x414d4548
    I/dalvikvm(13100):   | sysTid=13100 nice=0 sched=0/0 cgrp=apps handle=1074098536
    I/dalvikvm(13100):   | state=R schedstat=( 0 0 0 ) utm=877 stm=93 core=1
    I/dalvikvm(13100):   at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
    I/dalvikvm(13100):   at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:613)
    I/dalvikvm(13100):   at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:589)
    I/dalvikvm(13100):   at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:369)
    I/dalvikvm(13100):   at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:395)
    I/dalvikvm(13100):   at com.android.keyguard.KeyguardViewManager$1.onSetBackground(KeyguardViewManager.java:127)
    I/dalvikvm(13100):   at com.android.keyguard.KeyguardUpdateMonitor.dispatchSetBackground(KeyguardUpdateMonitor.java:452)
    I/dalvikvm(13100):   at com.android.keyguard.KeyguardViewManager$ViewManagerHost.setCustomBackground(KeyguardViewManager.java:302)
    

    nothing i have tried as of yet has worked, any ideas?

    EDITED

    to further clarify this is what sets the image in Settings:

            } else if (requestCode == REQUEST_PICK_WALLPAPER) {
                FileOutputStream wallpaperStream = null;
                try {
                    wallpaperStream = getActivity().openFileOutput(WALLPAPER_NAME,
                            Context.MODE_WORLD_READABLE);
    
                } catch (FileNotFoundException e) {
                    return; // NOOOOO
                }
                Uri selectedImageUri = getLockscreenExternalUri();
                Bitmap bitmap;
                if (data != null) {
                    Uri mUri = data.getData();
                    try {
                        bitmap = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(),
                                mUri);
                        bitmap.compress(Bitmap.CompressFormat.PNG, 100, wallpaperStream);
    
                        Toast.makeText(getActivity(), getResources().getString(R.string.
                                background_result_successful), Toast.LENGTH_LONG).show();
                        Settings.System.putInt(getContentResolver(),
                                Settings.System.LOCKSCREEN_BACKGROUND_STYLE, 1);
                        updateVisiblePreferences();
    
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } else {
                    try {
                        bitmap = BitmapFactory.decodeFile(selectedImageUri.getPath());
                        bitmap.compress(Bitmap.CompressFormat.PNG, 100, wallpaperStream);
                    } catch (NullPointerException npe) {
                        Log.e(TAG, "SeletedImageUri was null.");
                        Toast.makeText(getActivity(), getResources().getString(R.string.
                                background_result_not_successful), Toast.LENGTH_LONG).show();
                        super.onActivityResult(requestCode, resultCode, data);
                        return;
                    }
                }
    
            }
    
  • cphelps76
    cphelps76 about 10 years
    i added the code i'm using in settings to set the image to help clarify how i'm handling the image
  • cphelps76
    cphelps76 about 10 years
    could public boolean compress (Bitmap.CompressFormat format, int quality, OutputStream stream) be used to compress the image?
  • Sharjeel
    Sharjeel about 10 years
    The problem is not the function the problem is the size. Your device runs out of memory. Even if you optimize your solution it is not guaranteed that it will run on all devices. It's a better option to use a library that has been developed and used by top developers. It's just one line of code.
  • cphelps76
    cphelps76 about 10 years
    i agree but i doubt the rest of the team would be on board for using non google code for this sort of considering this exact same thing worked without issue prior to 4.4.2...but the above update looks like it gives me what i need