
本文介绍使用 Android PdfDocument API 将 ListView(或更推荐的 RecyclerView)中的条目逐页渲染并保存为标准 PDF 文件的完整实现方案,包含页面分页逻辑、字体适配与实际代码示例。
本文介绍使用 android `pdfdocument` api 将 listview(或更推荐的 recyclerview)中的条目逐页渲染并保存为标准 pdf 文件的完整实现方案,包含页面分页逻辑、字体适配与实际代码示例。
在 Android 开发中,直接将 ListView 内容“保存为 PDF”并非调用某个现成方法即可完成,而是需要手动将每个条目绘制到 PdfDocument.Page 的 Canvas 上,并合理处理分页、字体、行高与边距等排版细节。虽然你的代码尝试用 ObjectOutputStream 序列化列表数据(生成的是二进制 .txt 文件,非 PDF),但真正的 PDF 导出需借助系统原生的 android.graphics.pdf.PdfDocument 类——它自 Android 19(API 19)起可用,无需第三方依赖,生成标准、可读、跨平台兼容的 PDF。
⚠️ 注意:
ListView已属过时组件,官方推荐使用RecyclerView配合LinearLayoutManager实现更高效、灵活的列表管理。但若暂不重构 UI,你仍可基于其Adapter数据源(如barcodelist)进行 PDF 渲染,不建议直接绘制ListView视图本身(因视图未完全测量/布局,易导致NullPointerException或尺寸异常)。
✅ 推荐做法:从数据源生成 PDF(而非视图)
以下是以你现有 barcodelist 为基础的 PDF 导出核心逻辑(适配 ListView 场景,已封装为可复用方法):
private void exportToPdf() {
// 1. 创建 PDF 文档
PdfDocument pdfDocument = new PdfDocument();
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(14f);
// 2. 定义页面尺寸(A4: 595×842 点)
PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(595, 842, 1).create();
PdfDocument.Page page = pdfDocument.startPage(pageInfo);
Canvas canvas = page.getCanvas();
float margin = 50f;
float y = margin;
float lineHeight = 30f;
// 3. 逐行绘制条目(支持自动换页)
for (int i = 0; i < barcodelist.size(); i++) {
String item = barcodelist.get(i);
if (y + lineHeight > pageInfo.getPageHeight() - margin) {
// 当前行超出页面,结束当前页,开启新页
pdfDocument.finishPage(page);
pageInfo = new PdfDocument.PageInfo.Builder(595, 842, pdfDocument.getPages().size() + 1).create();
page = pdfDocument.startPage(pageInfo);
canvas = page.getCanvas();
y = margin;
}
canvas.drawText("Barcode " + (i + 1) + ": " + item, margin, y, paint);
y += lineHeight;
}
// 4. 结束最后一页并保存
pdfDocument.finishPage(page);
// 5. 保存到外部存储(需运行时权限)
File file = new File(getExternalFilesDir(null), "barcodes_export.pdf");
try (FileOutputStream fos = new FileOutputStream(file)) {
pdfDocument.writeTo(fos);
Toast.makeText(this, "PDF saved to: " + file.getAbsolutePath(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "Save failed: " + e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
pdfDocument.close();
}
}? 关键注意事项
-
权限要求:Android 10+ 需声明
android.permission.READ_MEDIA_DOCUMENTS或使用getExternalFilesDir()(如上例)避免请求广泛存储权限;Android 6–9 需动态申请WRITE_EXTERNAL_STORAGE。 -
字体与样式:
PdfDocument不支持复杂字体嵌入,建议使用系统默认字体(如Typeface.DEFAULT)并控制setTextSize()和setColor()保证可读性。 -
性能优化:若条目极多(>1000),建议在后台线程(如
AsyncTask或Coroutine)执行导出,避免阻塞主线程。 - 替代方案:如需更丰富功能(表格、图片、页眉页脚),可考虑轻量库如 iText7(免费版有限制)或 Apache PDFBox(需额外配置)。
✅ 最终集成到按钮点击事件
替换你原有 btnok.setOnClickListener 中的序列化逻辑为:
btnok.setOnClickListener(v -> {
if (barcodelist.isEmpty()) {
Toast.makeText(MainActivity.this, "No barcodes to export", Toast.LENGTH_SHORT).show();
return;
}
exportToPdf(); // 调用上方定义的方法
});通过此方案,你将获得一个结构清晰、分页合理、符合 PDF 标准的文档,且完全基于 Android 原生 API,无额外包体积负担。如后续升级至 RecyclerView,只需将 barcodelist 替换为 adapter.getCurrentList() 即可无缝迁移。



















