我正在使用itextg-5.5.4在我的Android应用程序中创建一个报告。创建报告包括填写现有pdf(封面页)上的一些字段,生成两个新的pdf(报告的两个部分),然后将创建的pdf附加到修改后的pdf。这没有问题。我已经成功地制作了所需的结果pdf。
每个报告只是一个包含100-300行,包含页眉和页脚的表格。
新任务是在每一行添加注释字段。我使用this作为参考。
生成报告所需的时间现在明显更长,最终会抛出OutOfMemoryError。此外,当它尝试创建新字段时,我可以看到GC不断运行。
这些是我收到的GC消息的单个实例。实际上有很多:
02-01 13:00:09.959: I/art(25619): Background sticky concurrent mark sweep GC freed 23578(976KB) AllocSpace objects, 0(0B) LOS objects, 5% free, 91MB/97MB, paused 9.704ms total 81.207ms
02-01 13:00:10.759: I/art(25619): Background partial concurrent mark sweep GC freed 415615(14MB) AllocSpace objects, 1(32KB) LOS objects, 15% free, 89MB/105MB, paused 9.521ms total 538.818ms
这是最终的错误:
02-01 13:45:40.182: E/art(28586): Throwing OutOfMemoryError "Failed to allocate a 28 byte allocation with 6 free bytes and 6B until OOM" (recursive case)
我在for循环之外创建单元格,并在循环数据时更新它们的内容。我在有问题的行上添加了一条评论,以明确错误发生的位置。
for(Bundle data : fac_data)
{
index++;
//Violations
violationtotals[0] = violationtotals[0] + data.getInt("Violation Count");
violationtotals[1] = violationtotals[1] + data.getInt("Uncorrected Violations");
//Device Inspections
//0=Total, 1=Tested, 2=Failed, 3=repaired
int [] pvb = new int[]{0,0,0,0};
int [] dcva = new int[]{0,0,0,0};
int [] rpd = new int[]{0,0,0,0};
pvb[0] = data.getInt("TOTAL PVB");
pvb[1] = data.getInt("Tested PVB");
pvb[2] = data.getInt("Failed PVB");
pvb[3] = data.getInt("Repaired PVB");
dcva[0] = data.getInt("TOTAL DCVA");
dcva[1] = data.getInt("Tested DCVA");
dcva[2] = data.getInt("Failed DCVA");
dcva[3] = data.getInt("Repaired DCVA");
rpd[0] = data.getInt("TOTAL RPD");
rpd[1] = data.getInt("Tested RPD");
rpd[2] = data.getInt("Failed RPD");
rpd[3] = data.getInt("Repaired RPD");
//Device Inspection Totals
pvbtotals[0] = pvbtotals[0] + pvb[0];
pvbtotals[1] = pvbtotals[1] + pvb[1];
pvbtotals[2] = pvbtotals[2] + pvb[2];
pvbtotals[3] = pvbtotals[3] + pvb[3];
dcvatotals[0] = dcvatotals[0] + dcva[0];
dcvatotals[1] = dcvatotals[1] + dcva[1];
dcvatotals[2] = dcvatotals[2] + dcva[2];
dcvatotals[3] = dcvatotals[3] + dcva[3];
rpdtotals[0] = rpdtotals[0] + rpd[0];
rpdtotals[1] = rpdtotals[1] + rpd[1];
rpdtotals[2] = rpdtotals[2] + rpd[2];
rpdtotals[3] = rpdtotals[3] + rpd[3];
//Package results
result.putIntArray(BundleKeys.report_violation_totals.toString(), violationtotals);
result.putIntArray(BundleKeys.report_rpd_totals.toString(), rpdtotals);
result.putIntArray(BundleKeys.report_dcva_totals.toString(), dcvatotals);
result.putIntArray(BundleKeys.report_pvb_totals.toString(), pvbtotals);
//Create Report PDF
//Index
indexCell.setPhrase(new Phrase(Integer.toString(index), smallFont));
MainTable.addCell(indexCell);
//Consumer Name and Address Cell
cnadCell.setPhrase((new Phrase(data.getString("Facility Name") + "\n\n" + data.getString("Address Line 1") + "\n" + data.getString("Address Line 2"), smallFont)));
MainTable.addCell(cnadCell);
//Categories of Concern Cell
cocCell.setPhrase(new Phrase(data.getString("Concerns"), smallFont));
MainTable.addCell(cocCell);
//Date of Inspection Cell
doiCell.setPhrase(new Phrase(data.getString("Inspection Date"), smallFont));
MainTable.addCell(doiCell);
//Violations Found Cell
violationFoundCell.setPhrase(new Phrase(Integer.toString(data.getInt("Violation Count")), smallFont));
MainTable.addCell(violationFoundCell);
//Violations Uncorrected Cell
violationUncorrectedCell.setPhrase(new Phrase(Integer.toString(data.getInt("Uncorrected Violations")), smallFont));
MainTable.addCell(violationUncorrectedCell);
//Handle nulls
String vstatus = data.getString("Violation Status");
if(vstatus == null)
{
vstatus = "";
}//if
//Violation Status Cell
violationStatusCell.setPhrase(new Phrase(data.getString(vstatus), smallFont));
MainTable.addCell(violationStatusCell);
//PVB device cells
MainTable.addCell(pvbLabel);
for(int i : pvb)
{
deviceValueCell.setPhrase(new Phrase(Integer.toString(i), smallFont));
MainTable.addCell(deviceValueCell);
}//for
//THIS IS THE NEW LINE
String commentName = annual ? "annual" : "quintennail";
inspectionCommentsLine.setCellEvent(new CommentField(commentName + Integer.toString(index)));
MainTable.addCell(inspectionCommentsLine);
//DCVA device cells
MainTable.addCell(dcvaLabel);
for(int i : dcva)
{
deviceValueCell.setPhrase(new Phrase(Integer.toString(i), smallFont));
MainTable.addCell(deviceValueCell);
}//for
//RPD Device Cells
MainTable.addCell(rpdLabel);
for(int i : rpd)
{
deviceValueCell.setPhrase(new Phrase(Integer.toString(i), smallFont));
deviceValueCell.setBorderWidthBottom(1.5f);
MainTable.addCell(deviceValueCell);
}//for
}//for
然后将MainTable添加到文档中。
这就是我自定义单元格事件的位置:
private class CommentField implements PdfPCellEvent
{
protected String fieldname;
public CommentField(String fieldname)
{
this.fieldname = fieldname;
}//Constructor
public void cellLayout(PdfPCell cell, Rectangle rectangle, PdfContentByte[] canvases)
{
final PdfWriter writer = canvases[0].getPdfWriter();
final TextField textField = new TextField(writer, rectangle, fieldname);
try
{
//THIS IS WHERE THE OutOfMemoryError POINTS TO IN STACK TRACE
final PdfFormField field = textField.getTextField();
writer.addAnnotation(field);
}//try
catch (final IOException ioe)
{
throw new ExceptionConverter(ioe);
}//catch
catch (final DocumentException de)
{
throw new ExceptionConverter(de);
}//catch
}//cellLayout
}//CommentField
我做错了吗?在pdf中有几百个字段是不是很糟糕?