1

My app uses images from the web to set wallpapers. However, when I try to use decodeStream using the BitmapFactory, some users on slower phones get an OutOfMemory exception. This image is never displayed on the app, it is just loaded, and then set as a wallpaper. I've searched online, but I've been unable to find any resources which help solve the problem.

Code:

public void setWallpaperMethod() {

    InputStream in = null;
    try {
        in = new java.net.URL(urldisplay).openStream();
    } catch (MalformedURLException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    final Bitmap bitmap = BitmapFactory.decodeStream(in);
    myWallpaperManager = WallpaperManager
            .getInstance(getApplicationContext());

    runOnUiThread(new Runnable() {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            try {
                myWallpaperManager.setBitmap(bitmap);
                Toast.makeText(MainActivity.this,
                        "Teamwork! Wallpaper set.", Toast.LENGTH_LONG)
                        .show();
            } catch (IOException e) {
                Toast.makeText(
                        MainActivity.this,
                        "Damnit, clickers! Wallpaper wasn't set. Try killing and restarting the app?",
                        Toast.LENGTH_LONG).show();
            }
        }

    });

}

The variable urldisplay is a string, equal to a URL (e.g., an imgur image). Also, the method is run in a thread, so there's no risk of the UI thread locking up.

So does anyone know how to solve this OutOfMemory Exception? All help appreciated.

djinne95
  • 275
  • 1
  • 3
  • 10
  • That is because the image is big for the device. Check that the image is not bigger than 1024. – Chefes Aug 06 '14 at 17:02
  • why don't you use `public void setStream (InputStream data)` instead of `setBitmap`? – njzk2 Aug 06 '14 at 17:02
  • njzk2: I made the code myself by stitching together code from several different sources, so it's probably not perfect :P – djinne95 Aug 06 '14 at 17:06
  • given that the question is about the wallpaper manager, and that the answers given in the duplicate question are a/ different from the accepted answer and b/ irrelevant in this case, and given that the accepted answer for this question is not applicable to the duplicate question, I vote for reopening the question. – njzk2 Aug 06 '14 at 18:21

2 Answers2

0

look at this link..

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

Android Documentation suggest that you downsample the image.. using this method to calculate the sample size:

public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}

then you would do something like this:

// First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

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

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
erik
  • 4,946
  • 13
  • 70
  • 120
0

Currently, you are opening an input stream, reading it, decoding a full fledge bitmap, then passing it to the manager, which will convert it to png and store it for later use.

Instead, you can open the input stream, pass it to the manager, which is now in charge of simply storing it for later use.

As you can see, that's one decoding and one encoding less.

Then, the wallpaper manager will be in charge of displaying the image, handling the image size accordingly.

myWallpaperManager = WallpaperManager
        .getInstance(getApplicationContext());
myWallpaperManager.setStream(in);

voila !

(That is assuming the wallpaper manager properly handles oversized images, but that is very likely the case)

njzk2
  • 38,969
  • 7
  • 69
  • 107
  • Thanks a lot, man! Just put this in my app, and it works fine on my phone :) So, will this work with slower phones now without throwing OutOfMemoryException? (i.e., Samsung Exhibit) – djinne95 Aug 06 '14 at 18:09
  • It should, yes. The wallpaper app should handle the image and make the necessary resampling if required. – njzk2 Aug 06 '14 at 18:20