Sharon Sharon - 5 months ago 11
Android Question

Android PDFDocument is producing a blank document

I'm using Android Studio and trying to get my app to produce a PDF. I've set up an Activity which generates the content that I want my PDF to have. This works fine if I let it display on screen. The onCreate part of the Activity is below:

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Connect to database
connectToDatabase();

// Set view
setContentView(R.layout.activity_export_pattern);

// find various views and set up their contents
// (I've left this bit out as it's quite long, but it doesn't contain
// anything controversial)

// Now try to export to PDF.
// Return success or failure to calling activity
// (basically just displays a toast indicating success/failure)
try {
if(exportToPDF()) {
Intent returnIntent = new Intent();
setResult(Activity.RESULT_OK, returnIntent);
finish();
}else {
Intent returnIntent = new Intent();
setResult(Activity.RESULT_CANCELED, returnIntent);
finish();
}
} catch (IOException e) {
e.printStackTrace();
Intent returnIntent = new Intent();
setResult(Activity.RESULT_CANCELED, returnIntent);
finish();
}
}


If I omit the final part (the try-catch), and just let it display on the screen, it works fine. The screen displays what I expect it to display.

However, to get it to create a PDF, I use the try-catch with the call to exportToPDF, which contains the following code (this is basically the code from the Android documentation, with a few changes as indicated by comments below):

public boolean exportToPDF() {
// Create PDF document
PdfDocument document = new PdfDocument();
// Create page description
// Line below changed as Android Studio was highlighting an error;
// instead of Rect, I have just put numbers.
// I've varied the numbers from 100 up to 1000, to no effect
PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(720, 720, 1).create();
// Start page
PdfDocument.Page page = document.startPage(pageInfo);
// Changed the line below from content = getContentView, as that was causing an error
// pageContent is the id of the overall LinearLayout in the XML file
// If I break after this in the debugger, content seems to have found the correct view and be populated with the appropriate page elements
View content = this.findViewById(R.id.pageContent);
// Added the line below after finding it suggested on here in another question
// Doesn't seem to make any difference
content.layout(0, 0, 200, 200);
if (content != null) {
content.draw(page.getCanvas());
}
// Finish page
document.finishPage(page);

// Write document content to external storage
// I'm using a FileOutputStream instead of BufferedOutputStream as given in the documentation, but, since this does at least produce a file, I don't think this is the source of the problem
String filename = this.item.getName() + ".pdf";
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + filename);
FileOutputStream fileOut = null;
try {
fileOut = new FileOutputStream(file);
document.writeTo(fileOut);
fileOut.close();
document.close();
return true;
} catch (IOException e) {
e.printStackTrace();
if(fileOut != null) fileOut.close();
document.close();
return false;
}
}


So, running this produces a pdf in the correct directory, named correctly, but it's blank. I've no idea what else to try, and would be grateful for any help! Thanks!

Answer

Where you writing view to PDF onCreate() in activity, it won't work and because your view returned 0 height and width. You need to wait for activity window to attached and then write view to pdf. You can try calling exportToPDF from onWindowFocusChanged() method of your activity.

public void onWindowFocusChanged(boolean hasFocus) {
    // TODO Auto-generated method stub
    super.onWindowFocusChanged(hasFocus);
try {
        if(exportToPDF()) {
            Intent returnIntent = new Intent();
            setResult(Activity.RESULT_OK, returnIntent);
            finish();
        }else {
            Intent returnIntent = new Intent();
            setResult(Activity.RESULT_CANCELED, returnIntent);
            finish();
        }
    } catch (IOException e) {
        e.printStackTrace();
        Intent returnIntent = new Intent();
        setResult(Activity.RESULT_CANCELED, returnIntent);
        finish();
    }

    }

You can also use ViewTreeObserver

 View content =  this.findViewById(R.id.pageContent);
    ViewTreeObserver vto = content.getViewTreeObserver(); 
            vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 
                @Override 
                public void onGlobalLayout() { 
              try {
            if(exportToPDF()) {
                Intent returnIntent = new Intent();
                setResult(Activity.RESULT_OK, returnIntent);
                finish();
            }else {
                Intent returnIntent = new Intent();
                setResult(Activity.RESULT_CANCELED, returnIntent);
                finish();
            }
        } catch (IOException e) {
            e.printStackTrace();
            Intent returnIntent = new Intent();
            setResult(Activity.RESULT_CANCELED, returnIntent);
            finish();
        }
content.getViewTreeObserver().removeGlobalOnLayoutListener(this);
    } 
            });