cphelps76
cphelps76

Reputation: 75

Out of memory on a 16571536 byte allocation

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

        }

Upvotes: 2

Views: 12558

Answers (1)

Sharjeel
Sharjeel

Reputation: 15798

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

Upvotes: 7

Related Questions