0

I'm having an OutOfMemoryError when trying to apply a wallpaper to device.

I'm using an AsyncTask and sometimes it works fine, but sometimes this happens.

May someone help me to optimize it even more? Thanks in advance.

AsyncTask code:

public class ApplyWallpaper extends AsyncTask<Void, String, Boolean> {
    private Context context;
    private Activity activity;
    private MaterialDialog dialog;
    private Bitmap resource;
    private View layout;
    private boolean isPicker;
    private Snackbar snackbar;

    public ApplyWallpaper(Context context, MaterialDialog dialog, Bitmap resource, Boolean isPicker, View layout) {
        this.activity = (Activity) context;
        this.context = context;
        this.dialog = dialog;
        this.resource = resource;
        this.isPicker = isPicker;
        this.layout = layout;
    }

    @Override
    protected Boolean doInBackground(Void... params) {
        WallpaperManager wm = WallpaperManager.getInstance(context);
        Boolean worked;
        try {
            wm.setBitmap(scaleToActualAspectRatio(resource));
            worked = true;
        } catch (IOException e2) {
            worked = false;
        }
        return worked;
    }

    @Override
    protected void onPostExecute(Boolean worked) {
        if (worked) {
            dialog.dismiss();
            Util.showSimpleSnackbar(layout,
                    context.getString(R.string.set_as_wall_done), 1);
        } else {
            String retry = context.getResources().getString(R.string.retry);
            snackbar = Snackbar
                    .make(layout, R.string.error, Snackbar.LENGTH_INDEFINITE)
                    .setAction(retry.toUpperCase(), new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            new ApplyWallpaper(context, dialog, resource, isPicker, layout);
                        }
                    });
            snackbar.setActionTextColor(context.getResources().getColor(R.color.accent));
            snackbar.show();
        }
        if (isPicker) {
            activity.finish();
        }

    }

    public Bitmap scaleToActualAspectRatio(Bitmap bitmap) {
        if (bitmap != null) {
            boolean flag = true;
            int deviceWidth = activity.getWindowManager().getDefaultDisplay()
                    .getWidth();
            int deviceHeight = activity.getWindowManager().getDefaultDisplay()
                    .getHeight();
            int bitmapHeight = bitmap.getHeight();
            int bitmapWidth = bitmap.getWidth();
            if (bitmapWidth > deviceWidth) {
                flag = false;
                int scaledHeight = deviceHeight;
                int scaledWidth = (scaledHeight * bitmapWidth) / bitmapHeight;
                try {
                    if (scaledHeight > deviceHeight)
                        scaledHeight = deviceHeight;
                    bitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth,
                            scaledHeight, true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (flag) {
                if (bitmapHeight > deviceHeight) {
                    int scaledHeight = deviceHeight;
                    int scaledWidth = (scaledHeight * bitmapWidth)
                            / bitmapHeight;
                    try {
                        if (scaledWidth > deviceWidth)
                            scaledWidth = deviceWidth;
                        bitmap = Bitmap.createScaledBitmap(bitmap, scaledWidth,
                                scaledHeight, true);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return bitmap;
    }

}

Wallpaper resource is loaded from:

Glide.with(context)
.load(linkForWallpaper)
.asBitmap()
.into(new SimpleTarget<Bitmap>() {
    @Override
    public void onResourceReady(final Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
        if (resource != null) {
            new ApplyWallpaper(context, dialogApply, resource,
                    false, layout, fab).execute();
        }
    }
});
Jahir Fiquitiva
  • 1,459
  • 3
  • 23
  • 47

3 Answers3

0

Add android:largeHeap="true" in your application tag inside Manifest file

<application
        android:name=".MyApplication"
        android:largeHeap="true"
        ........ >
</application>

It will increase an allocated memory to your app

What official document says :

android:largeHeap

Whether your application's processes should be created with a large Dalvik heap. This applies to all processes created for the application. It only applies to the first application loaded into a process; if you're using a shared user ID to allow multiple applications to use a process, they all must use this option consistently or they will have unpredictable results. Most apps should not need this and should instead focus on reducing their overall memory usage for improved performance. Enabling this also does not guarantee a fixed increase in available memory, because some devices are constrained by their total available memory.

To query the available memory size at runtime, use the methods getMemoryClass() or getLargeMemoryClass().

Bhargav Thanki
  • 4,924
  • 2
  • 37
  • 43
0

What is the original size of the bitmap you are loading? I encountered the same issue myself and the only way i was able to solve it is by first resize it to a much lower size than it originally was then loading it (i used picasso) scale it down and set it to the image view.

user2145673
  • 363
  • 1
  • 9
  • 23
-1

You decoded and parse bitmap all in once in scale...() method, that is extremely tasking, memory wise, you catch that and do again without calling that and it would go away with obvious lack of scaling

The key to scaling with a huge bitmap is to do the parsing and scaling in piecemeal and likely manually prior to set it in Wallpaper Manager. The piecemeal work is Canvas. android.graphics.Canvas if I remember right.