Java OutOfMemoryError uses Picasso images

Java OutOfMemoryError uses Picasso images … here is a solution to the problem.

Java OutOfMemoryError uses Picasso images

I’m trying to load an image into an ImageView and get an OutOfMemoryError. Images are dynamically displayed based on a specific View in ViewPager. However, after I continued scrolling through ViewPager, the image ended up failing to load and resulting in an OutOfMemoryError.

Notice that I have 4 Views in ViewPager and the app seems to crash on View 2. I’m guessing the size of the image is too big, but I’m under the impression that Picasso will handle it accordingly:

Picasso code:

Picasso.with(getActivity())
    .load(mImageURL)
    .fit()
    .memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_CACHE)
    .into((ImageView) rootView.findViewById(R.id.comments_image));

XML

<ImageView
    android:id="@+id/comments_image"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight=".525"
    android:background="@color/black">
</ImageView>

Error

java.lang.OutOfMemoryError: Failed to allocate a 5074572 byte allocation with 132096 free bytes and 129KB until OOM
     at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
     at android.graphics.Bitmap.nativeCreate(Native Method)
     at android.graphics.Bitmap.createBitmap(Bitmap.java:812)
     at android.graphics.Bitmap.createBitmap(Bitmap.java:789)
     at android.graphics.Bitmap.createBitmap(Bitmap.java:756)
     at android.graphics.drawable.VectorDrawable$VectorDrawableState.createCachedBitmapIfNeeded(VectorDrawable.java:713)
     at android.graphics.drawable.VectorDrawable.draw(VectorDrawable.java:280)
     at com.squareup.picasso.PicassoDrawable.draw(PicassoDrawable.java:105)
     at android.widget.ImageView.onDraw(ImageView.java:1176)
     at android.view.View.draw(View.java:15231)
     at android.view.View.updateDisplayListIfDirty(View.java:14167)
     at android.view.View.getDisplayList(View.java:14189)
     at android.view.View.draw(View.java:14959)
     at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
     at android.view.View.draw(View.java:15234)
     at android.view.View.updateDisplayListIfDirty(View.java:14167)
     at android.view.View.getDisplayList(View.java:14189)
     at android.view.View.draw(View.java:14959)
     at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
     at android.support.design.widget.CoordinatorLayout.drawChild(CoordinatorLayout.java:1131)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
     at android.view.View.updateDisplayListIfDirty(View.java:14162)
     at android.view.View.getDisplayList(View.java:14189)
     at android.view.View.draw(View.java:14959)
     at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
     at android.view.View.draw(View.java:15234)
     at android.support.v4.view.ViewPager.draw(ViewPager.java:2341)
     at android.view.View.updateDisplayListIfDirty(View.java:14167)
     at android.view.View.getDisplayList(View.java:14189)
     at android.view.View.draw(View.java:14959)
     at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
     at android.view.View.updateDisplayListIfDirty(View.java:14162)
     at android.view.View.getDisplayList(View.java:14189)
     at android.view.View.draw(View.java:14959)
     at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
     at android.support.v4.widget.DrawerLayout.drawChild(DrawerLayout.java:1373)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
     at android.view.View.updateDisplayListIfDirty(View.java:14162)
     at android.view.View.getDisplayList(View.java:14189)
     at android.view.View.draw(View.java:14959)
     at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
     at android.view.View.updateDisplayListIfDirty(View.java:14162)
     at android.view.View.getDisplayList(View.java:14189)
     at android.view.View.draw(View.java:14959)
     at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
     at android.view.View.updateDisplayListIfDirty(View.java:14162)
     at android.view.View.getDisplayList(View.java:14189)
     at android.view.View.draw(View.java:14959)
     at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
     at android.view.View.updateDisplayListIfDirty(View.java:14162)
     at android.view.View.getDisplayList(View.java:14189)
     at android.view.View.draw(View.java:14959)
     at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
     at android.view.View.updateDisplayListIfDirty(View.java:14162)
     at android.view.View.getDisplayList(View.java:14189)
     at android.view.View.draw(View.java:14959)
     at android.view.ViewGroup.drawChild(ViewGroup.java:3405)
     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3198)
     at android.view.View.draw(View.java:15234)
     at android.widget.FrameLayout.draw(F

Solution

I recommend that you use Glide because it is designed to work well by default on low-cost (and worst hardware) devices.

One big difference between Picasso and Glide is that the default format for Glide is RGB_565 while Picasso is ARGB_8888. As you can see below, doing the same job, it saves 50% memory compared to Picasso.

Memory cost

However, if you don’t want to change your library, you can try using the .resize(int, int) method to resize the image on Picasso’s builder.

Related Problems and Solutions