编辑:
glide
来加载图像。我得到了Out of Memory Error
。我在清单中使用了大堆true:
android:largeHeap="true"
滑翔版:
compile 'com.github.bumptech.glide:glide:3.7.0'
设备/ Android版本:
Nexus Device 6.0版本
我从Json得到的每张图片都是800kb到1mb。
activity_layout:
<RelativeLayout
android:id="@+id/home_layout_bottom"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/home_layout_top_recycler"
android:layout_margin="5dp">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_list_tab_home_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:scrollbars="vertical"
android:visibility="visible" />
<TextView
android:id="@+id/no_user_posts_item_tv_recycler"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/rv_list_tab_home_recycler"
android:layout_marginTop="80dp"
android:layout_centerHorizontal="true"
android:text="@string/txt_no_posts_available"
android:textColor="@color/txt_common_black"
android:textSize="@dimen/txt_size" />
</RelativeLayout>
适配器代码:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
final HomePostItems rowItem = getItem(position);
LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.lv_adapter_post_items_layout, null);
holder = new ViewHolder();
holder.ivPostedImage = (ImageView) convertView.findViewById(R.id.iv_posted_img);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
..................
Glide.with(context).load(rowItem.getPosteduserpostimage())
.placeholder(R.drawable.golive_load_image).error(R.drawable.golive_cancel_image)
.override(600, 200)
.into(holder.ivPostedImage);
adapter_layout.xml:
<RelativeLayout
android:id="@+id/rl_lv_user_post_adapter_img_holder_home"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginLeft="1dp"
android:layout_marginRight="1dp"
android:layout_below="@+id/tv_user_posted_msg_post_items_home" >
<ImageView
android:id="@+id/iv_posted_img_home"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:scaleType="fitXY"
android:background="#ffffff"
android:contentDescription="@string/cont_desc"/>
</RelativeLayout>
logcat的:
Request threw uncaught throwable
java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: Failed to allocate a 6365196 byte allocation with 865912 free bytes and 845KB until OOM
at java.util.concurrent.FutureTask.report(FutureTask.java:94)
at java.util.concurrent.FutureTask.get(FutureTask.java:164)
at com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor.afterExecute(FifoPriorityThreadPoolExecutor.java:96)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1121)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
at com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor$DefaultThreadFactory$1.run(FifoPriorityThreadPoolExecutor.java:118)
Caused by: java.lang.OutOfMemoryError: Failed to allocate a 6365196 byte allocation with 865912 free bytes and 845KB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:635)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:611)
at com.bumptech.glide.load.resource.bitmap.Downsampler.decodeStream(Downsampler.java:329)
at com.bumptech.glide.load.resource.bitmap.Downsampler.downsampleWithSize(Downsampler.java:220)
at com.bumptech.glide.load.resource.bitmap.Downsampler.decode(Downsampler.java:153)
at com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder.decode(StreamBitmapDecoder.java:50)
at com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder.decode(StreamBitmapDecoder.java:19)
at com.bumptech.glide.load.resource.bitmap.ImageVideoBitmapDecoder.decode(ImageVideoBitmapDecoder.java:39)
at com.bumptech.glide.load.resource.bitmap.ImageVideoBitmapDecoder.decode(ImageVideoBitmapDecoder.java:20)
at com.bumptech.glide.load.resource.gifbitmap.GifBitmapWrapperResourceDecoder.decodeBitmapWrapper(GifBitmapWrapperResourceDecoder.java:121)
at com.bumptech.glide.load.resource.gifbitmap.GifBitmapWrapperResourceDecoder.decodeStream(GifBitmapWrapperResourceDecoder.java:94)
at com.bumptech.glide.load.resource.gifbitmap.GifBitmapWrapperResourceDecoder.decode(GifBitmapWrapperResourceDecoder.java:71)
at com.bumptech.glide.load.resource.gifbitmap.GifBitmapWrapperResourceDecoder.decode(GifBitmapWrapperResourceDecoder.java:61)
at com.bumptech.glide.load.resource.gifbitmap.GifBitmapWrapperResourceDecoder.decode(GifBitmapWrapperResourceDecoder.java:22)
at com.bumptech.glide.load.engine.DecodeJob.decodeFromSourceData(DecodeJob.java:190)
at com.bumptech.glide.load.engine.DecodeJob.decodeSource(DecodeJob.java:177)
at com.bumptech.glide.load.engine.DecodeJob.decodeFromSource(DecodeJob.java:128)
at com.bumptech.glide.load.engine.EngineRunnable.decodeFromSource(EngineRunnable.java:122)
at com.bumptech.glide.load.engine.EngineRunnable.decode(EngineRunnable.java:101)
at com.bumptech.glide.load.engine.EngineRunnable.run(EngineRunnable.java:58)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
at com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor$DefaultThreadFactory$1.run(FifoPriorityThreadPoolExecutor.java:118)
我不知道如何解决这个OOM问题。如果您已经熟悉此问题,请分享您的建议。
可能采取不同的方法来解决这个问题。要实现这一目标,您可以使用不同的issues
ImageAdapter
这不会导致使用Glide.with(mActivity).loadFromMediaStore(_imageInfo.getmUri())
崩溃
为了更好地控制负载,请使用Glide v4执行以下操作
MediaStoreThumbFetcher
使用以下API,我们可以计算出剩余的可用内存和位图的大小
您可以检查可用内存和位图详细信息(如果需要)作为预检查
检查剩余的可用内存量
// usage:
Glide.with(mActivity).load(_imageInfo)....
// in GlideModule.registerComponents
registry.prepend(ImageInfo.class, ImageInfo.class, new UnitModelLoader.Factory<ImageInfo>());
registry.prepend(ImageInfo.class, Bitmap.class, new ImageInfoBitmapDecoder(context));
class ImageInfoBitmapDecoder implements ResourceDecoder<ImageInfo, Bitmap> {
private final ContentResolver contentResolver;
private final BitmapPool pool;
public ImageInfoBitmapDecoder(Context context) {
this.contentResolver = context.getContentResolver();
this.pool = Glide.get(context).getBitmapPool();
}
@Override public boolean handles(ImageInfo source, Options options) { return true; }
@Override public @Nullable Resource<Bitmap> decode(ImageInfo source, int width, int height, Options options) {
Bitmap thumb = Thumbnails.getThumbnail(contentResolver, source.getmId(), Thumbnails.MINI_KIND, null);
return BitmapResource.obtain(thumb, pool);
}
}
检查我们要加载的位图有多大
public static final float BYTES_IN_MB = 1024.0f * 1024.0f;
public static float megabytesFree() {
final Runtime rt = Runtime.getRuntime();
final float bytesUsed = rt.totalMemory();
final float mbUsed = bytesUsed/BYTES_IN_MB;
final float mbFree = megabytesAvailable() - mbUsed;
return mbFree;
}
public static float megabytesAvailable() {
final Runtime rt = Runtime.getRuntime();
final float bytesAvailable = rt.maxMemory();
return bytesAvailable/BYTES_IN_MB;
}
欲了解更多详情,请浏览private void readBitmapInfo() {
final Resources res = getActivity().getResources();
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, R.drawable.brasil, options);
final float imageHeight = options.outHeight;
final float imageWidth = options.outWidth;
final String imageMimeType = options.outMimeType;
Log.d(TAG, "w,h, type:"+imageWidth+", "+imageHeight+", "+imageMimeType);
Log.d(TAG, "estimated memory required in MB: "+imageWidth * imageHeight * BYTES_PER_PX/MemUtils.BYTES_IN_MB);
}
和Java methods to check memory and bitmap
这不是您问题的精确解决方案,但是您需要在使用Glide在列表中加载图像时记住这些事项。
您问题的主要威胁部分是图像大小。你得到的图像几乎是1mb!实际上,将它们显示为具有300多个项目的列表实际上太大了。因此,如果您也在服务器端,它总是建议使用几种不同大小的图像。
例如,如果显示朋友列表及其个人资料图片,我建议您先从服务器获取整个列表。然后获取所有配置文件图像并将其存储在本地。然后填充ListView
。并且最重要的部分是在将用户的个人资料图片上传到服务器时,在上传之后,服务器需要保持其几个大小,例如,低,中,高分辨率版本。因此,在为ListView
提供配置文件图片网址时,服务器可能会提供低分辨率的图像,因为它们最有可能用于缩略图。
使用RecyclerView
而不是ListView
也是一个很好的电话。但是当你处于低端设备时,它无法解决你在这里遇到的问题。
qazxsw poi与你无关可以通过编程方式解决。您需要将图像调整为较低版本。
您也可以查看Glide的OMM
。我建议你使用缓存策略,这样每次你不必从服务器加载图像。
祝好运。
使用Glide不保证没有caching mechanism错误,你需要使用几个小步骤来减少不能获得Out of Memory
的概率。
第1步:了解Glide中的OOM's
第2步:我更喜欢将caching mechanism加载到recyclerview
thumbnails
如果不需要更大或更高的图像,请记住始终要求小尺寸图像。
Glide
.with( context )
.load( UsageExampleGifAndVideos.gifUrl )
.thumbnail( 0.1f )
.into( imageView2 );
周围,也许你会发现一些有用的东西。使用Glide issues而不是recyclerView
。它可重复使用单个项目来渲染项目。我正在使用ListView
和glide
,我正在加载100多件物品的壁纸。
在ListView中,每次创建视图时,如果您有100多个视图,它将创建100多个视图,而在recyclelerview中,它会创建屏幕+2中有多少可见项目。
我遇到了类似的问题。我正在分享我解决它的方式。创建一个名为recyclerView
的文件夹,将你的drawable-nodpi
和golive_load_image
文件放入该文件夹,并从其他地方删除这两个图像文件,如golive_cancel_image
,drawable-ldpi
等(如果你有)。并添加drawable-hdpi
skipMemoryCache( true )
原因是在滚动时,滑动继续做图像处理甚至相关视图从列表中删除。在listview的onScrollStateChanged中添加此代码。
Glide.with(context).load(rowItem.getPosteduserpostimage())
.skipMemoryCache( true )
.placeholder(R.drawable.golive_load_image).error(R.drawable.golive_cancel_image)
.override(600, 200)
.into(holder.ivPostedImage);
if (view.getContext() != null) {
switch (scrollState) {
case SCROLL_STATE_IDLE:
Glide.with(view.getContext()).resumeRequests();
break;
case SCROLL_STATE_TOUCH_SCROLL:
case SCROLL_STATE_FLING:
Glide.with(view.getContext()).pauseRequests();
break;
}
}
).thumbnail(...f)
.skipMemoryCache(true)
停用磁盘缓存为了防止Out of Memory错误,可以采取预防措施以确保不会发生。所以这个问题的答案实际上是一堆可以暗示的建议。我也是。
正如@Reaz Murshed所建议的,我也建议将图像分成几种不同的尺寸。除此之外,我想补充一些可能有助于您分析此问题并解决问题的内容。
据我所知,OOM始终是一个使用错误,.diskCacheStrategy(DiskCacheStrategy.NONE)
只会延迟它;或者如果它是一个很大的负载,那么也许这是不可能的。所以我建议你按照largeHeap
链接来诊断内存泄漏。
this的堆栈痕迹对诊断它们毫无帮助。它只是告诉你它被打破了,一些东西填满了记忆。这种填充发生在抛出实际异常之前。这也意味着通常无论抛出什么,
OutOfMemoryErrors
实际上都不是罪魁祸首。唯一的例外是当想要分配内存的数量太大时,例如:要分配的数组大于最大内存,那么你就知道某些计算真的错了,就像一个32000x32000 @ 4图像会需要大约4GB的内存。如果可以重现:获取堆转储并分析应用程序的用法。正常的OOM诊断步骤:
- 重现异常(等到你在LogCat中看到它)
- 进行堆转储(分析内存泄漏)
- 分析大物体和泄漏
在上面的共享链接中,很少有关于OOM
和how to take heap dump?
的链接与此相同。
因此,我建议您分析内存泄漏并采取必要措施来防止OOM。
希望这会帮助你。