如何使用Glide为RecyclerView中每个PDF文件显示对应缩略图?
问题原因分析
- 异步线程与UI更新不同步:
onBindViewHolder里启动线程生成Bitmap,但Glide立刻加载未初始化的resultBitmap,线程执行完成后也没通知UI刷新,导致显示旧数据。 - 全局变量被多线程覆盖:多个线程共用
resultBitmap成员变量,最终所有Item都会显示最后生成的那张Bitmap。 - PDF转Bitmap逻辑错误:先创建空Bitmap并保存,之后才执行
page.render(),导致保存的文件是空图,且后续未利用缓存文件,直接用Bitmap既浪费资源又易出错。 - ViewHolder复用冲突:线程持有ViewHolder引用,当ViewHolder被复用时,线程完成后会错误更新到其他Item的UI上。
修复方案
1. 优化PDF缩略图生成方法
修正Bitmap生成逻辑,添加缓存机制避免重复生成,同时适配View尺寸减少内存占用:
private File generatePdfThumbnail(File pdfFile, ViewHolder holder) { File thumbnailFile = null; try { // 生成唯一缓存文件名,避免重复 String fileName = "pdf_thumb_" + pdfFile.hashCode() + ".jpg"; File cacheDir = new File(holder.itemView.getContext().getCacheDir(), "pdf_thumbs"); if (!cacheDir.exists()) { cacheDir.mkdirs(); } thumbnailFile = new File(cacheDir, fileName); // 缓存已存在则直接返回 if (thumbnailFile.exists()) { return thumbnailFile; } PdfRenderer renderer = new PdfRenderer(ParcelFileDescriptor.open(pdfFile, ParcelFileDescriptor.MODE_READ_ONLY)); if (renderer.getPageCount() > 0) { PdfRenderer.Page page = renderer.openPage(0); // 根据Item View尺寸缩放Bitmap,避免内存浪费 int targetWidth = holder.pdfImg.getWidth(); int targetHeight = holder.pdfImg.getHeight(); if (targetWidth == 0 || targetHeight == 0) { targetWidth = 200; targetHeight = 280; } float scale = Math.min((float) targetWidth / page.getWidth(), (float) targetHeight / page.getHeight()); int bitmapWidth = (int) (page.getWidth() * scale); int bitmapHeight = (int) (page.getHeight() * scale); Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY); // 保存Bitmap到缓存文件 FileOutputStream fos = new FileOutputStream(thumbnailFile); bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos); fos.close(); bitmap.recycle(); // 释放Bitmap内存 page.close(); } renderer.close(); } catch (Exception ex) { ex.printStackTrace(); Log.e("pdf_thumb_error", "生成缩略图失败"); } return thumbnailFile; }
2. 修复RecyclerView的onBindViewHolder方法
解决ViewHolder复用问题,确保线程完成后只更新对应位置的Item:
@Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { PidifyFile currentFile = files.get(position); holder.pdfName.setText(currentFile.getName()); Date lModified = currentFile.getDateCreated(); SimpleDateFormat sdf = new SimpleDateFormat("MMM dd, yyyy hh:mm aa"); holder.pdfDate.setText(sdf.format(lModified)); // 先显示占位图,避免加载延迟时显示旧数据 Glide.with(holder.itemView.getContext()) .load(R.drawable.pdf_placeholder) // 替换为你的占位图资源 .into(holder.pdfImg); // 启动线程生成缩略图,完成后回到UI线程更新 new Thread(() -> { File thumbFile = generatePdfThumbnail(new File(currentFile.getFilePath()), holder); final int currentPosition = holder.getAdapterPosition(); holder.itemView.post(() -> { // 检查当前holder是否仍对应原位置,避免复用错误 if (currentPosition == holder.getAdapterPosition() && thumbFile != null) { Glide.with(holder.itemView.getContext()) .load(thumbFile) .into(holder.pdfImg); } }); }).start(); }
额外优化建议
- 用Glide自定义Model加载PDF:封装PDF加载逻辑,让Glide自动处理异步和缓存,更贴合框架设计。
- 添加错误占位图:在Glide加载失败时显示错误图标,提升用户体验。
- 定期清理缓存:在应用退出或缓存占用过大时,清理
pdf_thumbs目录下的旧缓存文件。
内容的提问来源于stack exchange,提问作者Shivanshu Raj
相关产品推荐
相关产品推荐

