我正在扩展 PrintDocumentAdapter 以通过云打印将名册信息发送到打印机。一切正常,直到更改设置以减少文档中的页数。

例如,一张 table 可以放在两张 A4 纸上,但需要三张 A5 纸。云打印默认选择 A4,并生成预览。如果页面大小更改为 A5,则会按预期生成具有三页的新预览。如果随后将页面大小更改回 A4,云打印会显示消息“抱歉,这不起作用。再试一次”。并且必须退出。

这似乎是正在发生的事情:

  • onLayout() 使用 A4 文档属性调用。 LayoutResultCallback.onLayoutFinished() 被传递一个设置为 2 的 PrintDocumentInfo pageCount。
  • 正如预期的那样,
  • onWrite() 使用 0-1 的单个 PageRange 调用。
  • 我将纸张尺寸更改为 A5。
  • onLayout() 使用 A5 文档属性调用。 LayoutResultCallback.onLayoutFinished() 被传递一个设置为 3 的 PrintDocumentInfo pageCount。
  • onWrite() 使用 0-1 的单个 PageRange 调用, 是旧范围
  • onWrite() 被第二次调用,正确的 PageRange 为 0-2。

  • 这只会在旧的 PageRange 大于返回的页数时导致错误,但为什么 onWrite() 会被调用无效的 PageRange?

    我注意到我的设备上的许多应用程序只是简单地缩放输出,这样页数就不会在不同设置之间发生变化。他们这样做是因为这个问题吗?
    public class PrintAdapter extends PrintDocumentAdapter {
    
        private static final String TAG = "PrintAdapter";
    
        private PrintedPdfBuilder mPrintedPdfBuilder;
        private int mPages;
    
        public PrintAdapter(PrintedPdfBuilder printedPdfBuilder) {
            mPrintedPdfBuilder = printedPdfBuilder;
        }
    
        @Override
        public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
                             CancellationSignal cancellationSignal, LayoutResultCallback callback,
                             Bundle extras) {
    
            Log.v(TAG, "onLayout");
            // Respond to cancellation request
            if (cancellationSignal.isCanceled()) {
                callback.onLayoutCancelled();
                return;
            }
    
            int pages = mPrintedPdfBuilder.getPageCount(newAttributes);
            Log.v(TAG, "page count = " + pages);
            if (pages > 0) {
                // Return print information to print framework
                PrintDocumentInfo info = new PrintDocumentInfo
                        .Builder("print_output.pdf")
                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
                        .setPageCount(pages)
                        .build();
                // Content layout reflow is complete
                callback.onLayoutFinished(info, mPages != pages);
                mPages = pages;
            } else {
                // Otherwise report an error to the print framework
                callback.onLayoutFailed("Page count calculation failed.");
            }
        }
    
        @Override
        public void onWrite(PageRange[] ranges, ParcelFileDescriptor destination,
                            CancellationSignal cancellationSignal, WriteResultCallback callback) {
    
            Log.v(TAG, "onWrite() ranges: " + Arrays.toString(ranges));
            // Write PDF document to file
            try {
                PrintedPdfDocument pdf = mPrintedPdfBuilder.generateDocument(ranges);
    
                // check for cancellation
                if (cancellationSignal.isCanceled()) {
                    callback.onWriteCancelled();
                    mPrintedPdfBuilder.close();
                    return;
                }
                pdf.writeTo(new FileOutputStream(destination.getFileDescriptor()));
            } catch (IOException e) {
                callback.onWriteFailed(e.toString());
                return;
            } finally {
                mPrintedPdfBuilder.close();
            }
    
            PageRange[] writtenPages = mPrintedPdfBuilder.getWrittenPages();
            Log.v(TAG, "writtenPages: " + Arrays.toString(writtenPages));
            // Signal the print framework the document is complete
            callback.onWriteFinished(writtenPages);
        }
    }
    

    日志猫:
    08-28 11:46:44.187 9714-9714/com.meremammal.www.staffrosterwizard V/PrintAdapter: onLayout
    08-28 11:46:44.276 9714-9714/com.meremammal.www.staffrosterwizard V/PrintAdapter: page count = 2
    08-28 11:46:44.298 9714-9714/com.meremammal.www.staffrosterwizard V/PrintAdapter: onWrite() ranges: [PageRange[0 - 1]]
    08-28 11:46:44.512 9714-9714/com.meremammal.www.staffrosterwizard V/PrintAdapter: writtenPages: [PageRange[0 - 1]]
    08-28 11:46:50.418 9714-9714/com.meremammal.www.staffrosterwizard V/PrintAdapter: onLayout
    08-28 11:46:50.499 9714-9714/com.meremammal.www.staffrosterwizard V/PrintAdapter: page count = 3
    08-28 11:46:50.509 9714-9714/com.meremammal.www.staffrosterwizard V/PrintAdapter: onWrite() ranges: [PageRange[0 - 1]]
    08-28 11:46:50.678 9714-9714/com.meremammal.www.staffrosterwizard V/PrintAdapter: writtenPages: [PageRange[0 - 1]]
    08-28 11:46:50.918 9714-9714/com.meremammal.www.staffrosterwizard V/PrintAdapter: onWrite() ranges: [PageRange[0 - 2]]
    08-28 11:46:51.160 9714-9714/com.meremammal.www.staffrosterwizard V/PrintAdapter: writtenPages: [PageRange[0 - 2]]
    08-28 11:47:34.983 9714-9714/com.meremammal.www.staffrosterwizard V/PrintAdapter: onLayout
    08-28 11:47:35.049 9714-9714/com.meremammal.www.staffrosterwizard V/PrintAdapter: page count = 2
    08-28 11:47:35.056 9714-9714/com.meremammal.www.staffrosterwizard V/PrintAdapter: onWrite() ranges: [PageRange[0 - 2]]
    08-28 11:47:35.248 9714-9714/com.meremammal.www.staffrosterwizard V/PrintAdapter: writtenPages: [PageRange[0 - 1]]
    

    每次设置更改时都会调用 onLayout,但出于某种原因,然后使用之前的 PageRange[] 调用 onWrite

    最佳答案

    我捕获了 NullPointerException 错误并向用户显示了一条消息以供重试。这将捕获错误并将您的消息与重试按钮一起显示给用户,然后成功,因为 pageRanges 已更新。

        @Override
        public void onWrite(final PageRange[] pageRanges,
                            final ParcelFileDescriptor destination,
                            final CancellationSignal cancellationSignal,
                            final WriteResultCallback callback) {
            // Iterate over each page of the document,
            // check if it's in the output range.
            int requestedPageCount;
            for (int i = 0; i < mTotalPages; i++) {
                // Check to see if this page is in the output range.
                if (containsPage(pageRanges, i)) {
                    //########## Add in this Try Catch Block   #############
                    try {
                    //######################################################
                        PdfDocument.PageInfo newPage = new PdfDocument.PageInfo.Builder(mPageWidth,
                                mPageHeight, i).create();
                        PdfDocument.Page page =
                                mPDFDocument.startPage(newPage);
                        if (cancellationSignal.isCanceled()) {
                            callback.onWriteCancelled();
                            mPDFDocument.close();
                            mPDFDocument = null;
                            return;
                        }
                        if (mPrintJobType == PrintType.LIST) {
                            drawPageList(page, i + 1, (mPageWidth < mPageHeight));
                        } else {
                            drawPageDetail(page, i);
                        }
                        mPDFDocument.finishPage(page);
                    //######## Catch the error here and display a message
                    } catch (NullPointerException e) {
                        //Catch a known error thrown thrown by pageRanges not being updated in a timely manner.
                        callback.onWriteFailed("We found a bug in the Android operating system. " +
                                "Please click Retry to continue.");
                        return;
                    }
                    //##################################################
                }
            }
    
            // Write PDF document to file
            try {
                mPDFDocument.writeTo(new FileOutputStream(
                        destination.getFileDescriptor()));
            } catch (IOException e) {
                callback.onWriteFailed(e.toString());
                return;
            } finally {
                mPDFDocument.close();
                mPDFDocument = null;
            }
            callback.onWriteFinished(pageRanges);
        }
    

    10-08 17:45