RecyclerView中使用Fresco仍出现OOM问题求助
遇到在RecyclerView里切换到Fresco还是遭遇OOM的情况确实挺闹心的,我结合实际开发经验给你几个针对性的排查和解决方向:
自定义Fresco内存缓存配置,限制内存占用
Fresco默认的内存缓存设置可能在内存紧张的设备上还是会占用过多资源。你可以在初始化Fresco时手动调整内存缓存的上限,比如设置为应用最大可用内存的1/8:ImagePipelineConfig config = ImagePipelineConfig.newBuilder(context) .setBitmapMemoryCacheParamsSupplier(() -> { int maxCacheSize = (int) (Runtime.getRuntime().maxMemory() / 8); return new MemoryCacheParams( maxCacheSize, Integer.MAX_VALUE, maxCacheSize, Integer.MAX_VALUE, Integer.MAX_VALUE); }) .build(); Fresco.initialize(context, config);这样能避免Fresco的内存缓存无限制膨胀,减少OOM风险。
强制压缩图片到View实际尺寸
很多OOM都是因为加载了远大于View显示尺寸的原图导致的。你可以在构建ImageRequest时添加ResizeOptions,让Fresco自动把图片压缩到View的大小:// 注意:确保holder.image已经完成测量,能拿到正确的宽高 ImageRequest request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(item.getImageUrl())) .setResizeOptions(new ResizeOptions(holder.image.getWidth(), holder.image.getHeight())) .setLocalThumbnailPreviewsEnabled(true) .build(); DraweeController controller = Fresco.newDraweeControllerBuilder() .setImageRequest(request) .setOldController(holder.image.getController()) .setAutoPlayAnimations(true) .build(); holder.image.setController(controller);如果在
onBindViewHolder时View还没完成测量,你可以通过ViewTreeObserver监听测量完成事件后再设置请求,或者根据布局预估一个合理的尺寸。在ViewHolder回收时主动释放资源
确保RecyclerView的ViewHolder被回收时,Fresco的控制器也能及时释放。重写onViewRecycled方法:@Override public void onViewRecycled(@NonNull ViewHolder holder) { super.onViewRecycled(holder); // 断开控制器,释放相关内存资源 holder.image.setController(null); }排查其他内存泄漏点
有时候OOM不一定是Fresco的锅,你可以用Android Studio的Profiler工具生成内存快照,分析是否有其他长生命周期对象(比如上下文、回调)被ViewHolder或数据项持有导致内存泄漏。尝试关闭硬件加速(最后备选)
部分设备上的硬件加速可能会导致额外的内存开销,你可以给DraweeView关闭硬件加速试试:<!-- 在布局中设置 --> <com.facebook.drawee.view.SimpleDraweeView ... android:hardwareAccelerated="false" />或者在代码中设置:
holder.image.setLayerType(View.LAYER_TYPE_SOFTWARE, null);这个操作可能会影响图片加载性能,建议只在其他方案无效时尝试。
更新到最新版Fresco
旧版本的Fresco可能存在已知的内存泄漏bug,升级到最新的稳定版本说不定能直接解决问题。
内容的提问来源于stack exchange,提问作者Sourav Nag

