【问题标题】:Android long text paginationAndroid长文本分页
【发布时间】:2016-03-28 18:52:57
【问题描述】:

我需要显示大型文本文件。无需滚动即可显示文本作为电子书。我可以打断页面上的长文本,但这需要我太多时间。例如 - 以下代码处理 1.4 MB 的文本大约 10-15 秒。

    public void split(TextPaint textPaint, String filepath,Context context) {
        int pages = 0;
        File file = new File(filepath);
        char[] bufferChar = new char[1024];
        String uncompletedtext="";
        //How lines we can show
        int maxLinesOnpage = 0;
        StaticLayout staticLayout = new StaticLayout(
                context.getString(R.string.lorem_ipsum),
                textPaint,
                pageWidth,
                Layout.Alignment.ALIGN_NORMAL,
                lineSpacingMultiplier,
                lineSpacingExtra,
                false
        );
        int startLineTop = staticLayout.getLineTop(0);
        int endLine = staticLayout.getLineForVertical(startLineTop + pageHeight);
        int endLineBottom = staticLayout.getLineBottom(endLine);
        if (endLineBottom > startLineTop + pageHeight) {
            maxLinesOnpage = endLine - 1;
        } else {
            maxLinesOnpage = endLine;

        }


        //let's paginate
try {
            BufferedReader buffer = new BufferedReader(new FileReader(file));
            while (buffer.read(bufferChar)>=0) {
                uncompletedtext += new String(bufferChar);
                boolean allcomplete = false;


                    staticLayout = new StaticLayout(
                            uncompletedtext,
                            textPaint,
                            pageWidth,
                            Layout.Alignment.ALIGN_NORMAL,
                            lineSpacingMultiplier,
                            lineSpacingExtra,
                            false
                    );
                    staticLayout.getLineCount();
                    int curTextPages= (int) Math.floor(staticLayout.getLineCount() / maxLinesOnpage);
                    uncompletedtext=uncompletedtext.substring(staticLayout.getLineEnd(curTextPages));
                    pages+=curTextPages;
                    Log.e("PAGES","" + pages);



            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        Log.e("FILE READED FULLY!!", "READ COMPLETE!!!!!!!!!!!!!!!!");




    }

太长了。我无法理解 FBReader 和СoolReader 等应用程序如何立即处理大文件(超过 9 MB)。 我看到了应用程序的来源,但它们的功能太多,无法快速找到答案。 我真的需要帮助和提示。谢谢。

【问题讨论】:

  • Paginating text in Android有帮助吗?...
  • 这是一个很好的解决方案,但不适用于大文本。
  • 在每个 while (buffer.read(bufferChar)>=0) 循环迭代中创建一个新的 StaticLayout 实例。这是一项昂贵的操作,可能会导致性能问题。
  • 是的,你是对的。我找到解决方案。需要使用RandomAccessFile

标签: java android pagination


【解决方案1】:

谢谢大家!我找到解决方案!不优雅但非常快的代码(10Mb ~ 600 ms)

public void split(TextPaint textPaint, String filepath,Context context) {
        File file = new File(filepath);
        char[] bufferChar = new char[512];
        //How lines on page
        int maxLinesOnpage = 0;
        int symbolsOnLine = 0;
        StaticLayout staticLayout = new StaticLayout(
                context.getString(R.string.lorem_ipsum),//short text with 100 lines (\r\n\r\n\r\n\r\n\r\n\r\n)
                textPaint, //MONOSPACE!!!
                pageWidth,
                Layout.Alignment.ALIGN_NORMAL,
                lineSpacingMultiplier,
                lineSpacingExtra,
                false
        );
        int startLineTop = staticLayout.getLineTop(0);
        int endLine = staticLayout.getLineForVertical(startLineTop + pageHeight);
        int endLineBottom = staticLayout.getLineBottom(endLine);
        if (endLineBottom > startLineTop + pageHeight) {
            maxLinesOnpage = endLine - 1;
        } else {
            maxLinesOnpage = endLine;
        }
        symbolsOnLine = staticLayout.getLineEnd(0);

        try {
            RandomAccessFile rac = new RandomAccessFile(file, "r");
            byte[] buffer = new byte[2048];
            int wordLen = 0; //Length of word in symbols
            int wordInBytes = 0; //Lenght of word
            int startLinePos = 0; //Start first line position
            int lineWidth = 0; //Current line length
            int totalLines =0; //Total lines on current page
            Log.e("Start pagination", "" + totalLines);
            long timeout= System.currentTimeMillis();
            int buflen=0; //buffer size
            int totalReadedBytes = 0; //Total bytes readed
            byte skipBytes = 0;
            while ( (buflen=rac.read(buffer))!=-1){
                for (int i=0;i<buflen;i++) {
                    totalReadedBytes++;
                    wordInBytes++;
                    if (skipBytes==0){ //Bytes on one symbol
                        if (unsignedToBytes(buffer[i])>=192){skipBytes=2;}
                        if (unsignedToBytes(buffer[i])>=224){skipBytes=3;}
                        if (unsignedToBytes(buffer[i])>=240){skipBytes=4;}
                        if (unsignedToBytes(buffer[i])>=248){skipBytes=5;}
                        if (unsignedToBytes(buffer[i])>=252){skipBytes=6;}
                    }
                    //Full bytes on symbol or not
                    if (skipBytes>0){
                        skipBytes--;
                        if (skipBytes>0){continue;}
                    }

                    if (buffer[i] == 13) {//We have a \r symbol. Ignore.
                        continue;
                    }



                    if (buffer[i]==10){//New line symbol
                        if (lineWidth + wordLen>symbolsOnLine){
                            totalLines++;
                            if (totalLines > maxLinesOnpage) {
                                int[] pgsbytes = {startLinePos, totalReadedBytes};
                                pages.add(pgsbytes);
                                startLinePos = totalReadedBytes ;
                                totalLines = 0;
                            }
                        }
                        wordLen=0;
                        wordInBytes=0;
                        totalLines++;
                        lineWidth=0;
                        if (totalLines>maxLinesOnpage){
                            int[] pgsbytes = {startLinePos, totalReadedBytes-1};
                            pages.add(pgsbytes);
                            startLinePos = totalReadedBytes-1;
                            totalLines=0;
                        }
                    }

                    if (buffer[i]==32){//Space symbol
                        if (lineWidth + wordLen+1<=symbolsOnLine){//Word fits in line
                            lineWidth+=wordLen + 1;
                            wordLen=0;
                            if (lineWidth==symbolsOnLine){
                                totalLines++;
                                if (totalLines > maxLinesOnpage) {
                                    int[] pgsbytes = {startLinePos, totalReadedBytes};
                                    pages.add(pgsbytes);
                                    startLinePos = totalReadedBytes ;
                                    totalLines = 0;
                                }
                                lineWidth = 0;
                                wordLen = 0;
                                wordInBytes=0;
                            }
                        } else {
                            if (lineWidth + wordLen==symbolsOnLine){
                                totalLines++;
                                if (totalLines > maxLinesOnpage) {
                                    int[] pgsbytes = {startLinePos, totalReadedBytes};
                                    pages.add(pgsbytes);
                                    startLinePos = totalReadedBytes ;
                                    totalLines = 0;
                                }
                                lineWidth = 0;
                                wordLen = 0;
                                wordInBytes=0;
                            } else {
                                totalLines++;
                                if (totalLines > maxLinesOnpage) {
                                    int[] pgsbytes = {startLinePos, totalReadedBytes - 1 - wordInBytes};
                                    pages.add(pgsbytes);
                                    startLinePos = totalReadedBytes - 1;
                                    totalLines = 0;
                                }
                                lineWidth = wordLen + 1;
                                wordLen = 0;
                                wordInBytes=0;
                            }
                        }
                    }

                    if (buffer[i]!=32&&buffer[i]!=10&&buffer[i]!=13){wordLen++; }
                    if (wordLen==symbolsOnLine){
                        totalLines++;
                        if (totalLines>maxLinesOnpage){
                            int[] pgsbytes = {startLinePos, totalReadedBytes-1  - wordInBytes};
                            pages.add(pgsbytes);
                            startLinePos = totalReadedBytes-1;
                            totalLines=0;
                        }
                        lineWidth=0;
                        wordLen=0;
                        wordInBytes=0;
                    }
                }

            }
            rac.close();
            timeout = System.currentTimeMillis() - timeout;
            Log.e("TOTAL Time",  " time " + timeout + "ms");
        } catch (Exception e) {
            e.printStackTrace();
        }

        Log.e("FILE READED FULLY!!", "READ COMPLETE!!!!!!!!!!!!!!!!");
    }

【讨论】:

  • 我有像你这样的问题。但我不明白你的解决方案。你能为我分享分页文本的完整代码吗?我用我的文本文件(~6mb)尝试上面的代码,这需要我 6 秒。
  • 嗨@SlyBeaver。我使用 StaticLayout 并有 16,000 行。为什么使用 100 行的短文本?我可以将这些代码用于我自己的目的吗?
  • @SlyBeaver 请回答我。
  • @SlyBeaver 。这对我很重要。如果您在线,请告诉我。
  • 如果您想从文件中读取长文本并对其进行分页,则需要此代码。是的,您可以在您的代码上使用此代码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-28
  • 2012-05-26
  • 1970-01-01
  • 2012-12-19
  • 2015-07-26
  • 1970-01-01
相关资源
最近更新 更多