Android RecyclerView图片加载内存优化:Glide与Fresco选型困境
问题概述
我开发了一款从API获取带图片数据的App,用RecyclerView展示图片,支持滚动加载更多。测试了Glide和Fresco两款图片加载库,目前Glide内存表现更好,但图片存在模糊问题;Fresco图片清晰但内存占用过高。相关代码和内存数据如下:
Glide 实现细节
图片加载代码
Glide.with(holder.gameImage) .load(itemViewModel.thumb) .skipMemoryCache(true) .apply(RequestOptions().override(holder.gameImage.width, holder.gameImage.height)) .centerInside() .diskCacheStrategy(DiskCacheStrategy.ALL) .format(DecodeFormat.PREFER_RGB_565) .error(R.drawable.no_image_found) .into(holder.gameImage)
RecyclerView 视图回收代码
override fun onViewRecycled(holder: ViewHolder) { super.onViewRecycled(holder) Glide.with(holder.gameImage).clear(holder.gameImage) }
加载150+条目后的内存占用

Fresco 实现细节
图片加载代码
val frescoRequest: ImageRequest = ImageRequestBuilder .newBuilderWithSource(itemViewModel.thumb.toUri()) .setResizeOptions(ResizeOptions(holder.layout.width,holder.layout.height)).build() holder.gameImage.controller = Fresco.newDraweeControllerBuilder().setOldController(holder.gameImage.controller).setImageRequest(frescoRequest).build()
加载150+条目后的内存占用

测试中发现的核心问题
- 测试时Fresco用ARGB_8888格式,Glide用RGB_565格式
- 两款库都把图片缩放到和ImageView相同尺寸,但Fresco内存更高、图片更清晰,Glide图片模糊
- 尝试调整图片格式平衡内存与清晰度,但要么模糊,要么内存飙到250MB;另外内存分析器里近50MB的「Others」是什么原因?
解决方案与分析
一、修复Glide图片模糊问题
1. 调整图片解码格式
你用的DecodeFormat.PREFER_RGB_565是模糊的核心原因——这个格式每个像素仅占2字节,色彩精度远低于ARGB_8888(4字节)。要兼顾清晰度和内存:
- 改用
DecodeFormat.PREFER_ARGB_8888,同时限制Glide内存缓存大小避免暴涨:
自定义Glide配置类:@GlideModule class CustomGlideModule : AppGlideModule() { override fun applyOptions(context: Context, builder: GlideBuilder) { // 根据设备内存设置合理缓存,比如20MB val cacheSize = 20 * 1024 * 1024 // 20MB builder.setMemoryCache(LruResourceCache(cacheSize.toLong())) } } - 如果坚持用RGB_565,必须确保缩放尺寸准确:
holder.gameImage.width/height在onBindViewHolder时可能还没完成测量(返回0或默认值),导致图片错误缩放。可以监听控件测量完成后再加载:holder.gameImage.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { holder.gameImage.viewTreeObserver.removeOnGlobalLayoutListener(this) // 用实际测量后的尺寸加载图片 Glide.with(holder.gameImage) .load(itemViewModel.thumb) .override(holder.gameImage.width, holder.gameImage.height) .format(DecodeFormat.PREFER_RGB_565) .into(holder.gameImage) } })
2. 更换缩放策略
当前的centerInside()会保持图片比例,若原图尺寸小于ImageView,会被拉伸导致模糊。可以换成:
fitCenter():保持比例,让图片完全覆盖ImageView(超出部分裁剪),原图尺寸足够时清晰度更好centerCrop():裁剪图片中心区域适配ImageView,避免拉伸模糊,适合需要填充控件的场景
3. 开启内存缓存
你设置了skipMemoryCache(true),会导致每次滚动都要重新从磁盘解码图片,反而增加内存波动。建议关闭这个设置,让Glide缓存解码后的图片到内存,减少重复解码开销。
二、平衡内存与清晰度的通用方案
Glide侧优化
除上述调整外,还可以:
- 启用
DiskCacheStrategy.RESOURCE,只缓存解码后的图片,减少磁盘缓存的内存占用 - 用
thumbnail(0.5f)加载缩略图后再加载原图,提升滚动流畅度同时降低内存峰值
Fresco侧优化
如果想保留Fresco的清晰度同时降低内存:
- 在ImageRequest中设置RGB_565格式:
val decodeOptions = ImageDecodeOptions.newBuilder() .setPreferredBitmapConfig(Bitmap.Config.RGB_565) .build() val frescoRequest = ImageRequestBuilder .newBuilderWithSource(itemViewModel.thumb.toUri()) .setImageDecodeOptions(decodeOptions) .setResizeOptions(ResizeOptions(holder.layout.width, holder.layout.height)) .build() - 自定义Fresco内存缓存大小:
val pipelineConfig = ImagePipelineConfig.newBuilder(context) .setBitmapMemoryCacheParamsSupplier { MemoryCacheParams( 20 * 1024 * 1024, // 最大缓存20MB 100, // 最大缓存条目数 20 * 1024 * 1024, 100, Long.MAX_VALUE ) } .build() Fresco.initialize(context, pipelineConfig)
三、关于内存分析器「Others」的说明
「Others」通常包含以下几类内存:
- Native层内存:比如Fresco默认将图片缓存到Native内存,这部分不会计入Java堆,所以会归类到Others
- 未归类的临时对象:图片解码、磁盘缓存读写产生的临时内存对象
- 系统资源:未关闭的文件流、网络连接、JNI引用等
- 第三方库未识别内存:部分第三方库的内存分配未被Android Studio分析器归类
如果你的App中Others占50MB,大概率是Fresco的Native缓存导致的。可以通过以下方式排查:
- 用Android Studio Profiler的「Native Memory」面板查看具体分配情况
- 禁用磁盘缓存后观察Others是否减少,判断是否是缓存导致
- 检查是否有未释放的资源(比如网络请求、文件流)引发内存泄漏
内容的提问来源于stack exchange,提问作者YOUSEF -ELSAYED
相关产品推荐
相关产品推荐

