Java OutOfMemoryError 使用 Picasso 图片

3

我想将一张图片加载到ImageView上,但是收到了OutOfMemoryError错误。该图片根据ViewPager中特定的视图动态显示。然而,当我不断滚动ViewPager时,图片最终无法加载并导致OutOfMemoryError错误。

请注意,ViewPager中有4个视图,该应用程序似乎在第2个视图上崩溃。我猜测图片的大小实际上过大,但我认为Picasso可以相应地处理:

Picasso 代码:

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>

错误
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

图像的分辨率是多少? - Vucko
我知道它是359.2 KB,而且它太大了,但我希望了解Picasso如何压缩以防止此错误。该图像位于此处:https://s3.amazonaws.com/fan-polls/Durant.jpg - tccpg288
据我之前的理解,这更多与分辨率有关,而不是尺寸。虽然我对Picasso不是很熟悉,但我听说过它。希望其他人能够更好地帮助你。 - Vucko
2个回答

3
我建议您使用Glide,因为它默认情况下可以在低成本(和最差的硬件)设备上良好运行。
Picasso和Glide之间的一个很大的区别是,当Picasso的默认格式为ARGB_8888时,Glide的默认格式为RGB_565。如下所示,与Picasso相比,执行相同任务的内存成本降低了50%。 内存成本 不过,如果您不想更改库,可以尝试使用.resize(int, int)方法在Picasso的构建器上调整图像大小。

我注意到错误发生在三星模拟器上,但我同时运行的HTC模拟器没有任何问题。 - tccpg288
我想设置一个100Kb的最大值,有任何关于如何实现这一点的想法吗? - tccpg288
我绝对不能使用另一个库。我使用Picasso进行一些图像修改,这对我的应用程序至关重要。 - tccpg288
但是我并不只是让你改变你的库。请阅读“仍然……”段落。 - Lucas Albuquerque
1
我从Picasso切换到Glide,甚至能够减少大堆使用。它的表现非常出色。 - Christophe Chenel
显示剩余2条评论

1

您在清单文件中设置了android:largeheap="true"吗?

<application
    android:name=".MyApplication"
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="MyApplication"
    android:largeHeap="true"*
    android:logo="@drawable/logo_for_up"
    android:screenOrientation="portrait"
    android:theme="@style/AppTheme" >
</application>

在我实施它之前,你能帮我理解一下这个代码的实际作用是什么吗? - tccpg288
在API Level 11+上运行的应用程序可以在清单文件中的<application>元素上具有android:largeHeap="true",以请求比正常堆大小更大的堆大小,并且ActivityManager上的getLargeMemoryClass()将告诉您该堆的大小。 - Vivek Faldu
然而,无法保证大堆大小有多大。用户将会察觉到您的大堆请求,因为它将迫使他们的其他应用程序退出RAM终止其他应用程序的进程,以释放系统RAM供您的大堆使用。 - Vivek Faldu
使用Glide,不要费心去处理任何大堆内存。此外,使用大堆内存会影响垃圾回收器,从而使应用程序变慢。 - Christophe Chenel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接