加载Bitmap时RecyclerView滚动卡顿,Glide加载PDF转Bitmap列表怎么优化滑动
RecyclerView加载PDF预览图卡顿优化方案
卡顿核心原因
- 你当前在主线程执行
pdfToBitmap转换逻辑,PDF渲染属于重度耗时操作,直接阻塞主线程导致掉帧 - 生成的Bitmap使用PDF原尺寸,远大于列表ImageView的实际展示尺寸,占用内存过高,频繁触发GC导致卡顿
- 直接传入Bitmap给Glide加载,Glide无法直接关联PDF文件做缓存,每次滑动都要重新转换Bitmap,重复消耗资源
优化方案
1. 不要在主线程执行PDF转换逻辑
绝对不要在onBindViewHolder中同步调用pdfToBitmap方法,将转换逻辑放到异步线程执行,最优方案是通过Glide自定义ModelLoader,让Glide在自身维护的异步线程池中完成转换,同时自动复用缓存机制。
2. 优化PDF转Bitmap逻辑,按目标尺寸采样
不要使用PDF原宽高生成Bitmap,按实际要展示的ImageView尺寸缩放,大幅降低内存占用,优化后的转换代码如下:
public static Bitmap pdfToBitmap(File pdfFile, int targetWidth, int targetHeight) { Bitmap bitmap = null; ParcelFileDescriptor fd = null; PdfRenderer renderer = null; PdfRenderer.Page page = null; try { fd = ParcelFileDescriptor.open(pdfFile, ParcelFileDescriptor.MODE_READ_ONLY); renderer = new PdfRenderer(fd); if (renderer.getPageCount() <= 0) { return null; } page = renderer.openPage(0); // 计算适配目标尺寸的最小缩放比例,避免生成过大Bitmap float scale = Math.min((float) targetWidth / page.getWidth(), (float) targetHeight / page.getHeight()); int width = Math.round(page.getWidth() * scale); int height = Math.round(page.getHeight() * scale); bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY); return bitmap; } catch (Exception ex) { if (bitmap != null) bitmap.recycle(); ex.printStackTrace(); return null; } finally { if (page != null) page.close(); if (renderer != null) renderer.close(); try { if (fd != null) fd.close(); } catch (Exception e) { e.printStackTrace(); } } }
3. 调整Glide加载逻辑,启用缓存
直接将PDF文件作为输入源传给Glide,不要提前转Bitmap,同时配置缓存策略,避免重复转换:
Glide.with(viewHolder.itemView.getContext()) .load(pdfFile) // 直接传入PDF文件对象 .override(200, 300) // 按列表预览图的实际固定尺寸填写,避免动态测量耗时 .diskCacheStrategy(DiskCacheStrategy.RESOURCE) // 缓存转换后的Bitmap .placeholder(R.drawable.your_placeholder) // 增加占位图,避免滑动时留白 .into(viewHolder.pdfImg);
4. RecyclerView基础配置优化
- 给RecyclerView设置
setHasFixedSize(true),避免重复测量布局 - 开启列表预加载:
recyclerView.setInitialPrefetchItemCount(4) - 滑动时暂停Glide加载,减少滑动时的资源占用:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == RecyclerView.SCROLL_STATE_FLING) { Glide.with(recyclerView.getContext()).pauseRequests(); } else { Glide.with(recyclerView.getContext()).resumeRequests(); } } });
内容的提问来源于stack exchange,提问作者Shivanshu Raj
相关产品推荐
相关产品推荐

