FBReaderv 1.8.2 启动,阅读流程,及显示研究

优质
小牛编辑
124浏览
2023-12-01

一.在AndroidManifest.xml中找到 

    <application android:name="org.geometerplus.android.fbreader.FBReaderApplication" android:icon="@drawable/fbreader" android:logo="@drawable/fbreader_bw" android:label="FBReader">

可以看到应用程序的入口为FBReaderApplication 

找到FBReaderApplication的类,里面定义如下 

public class FBReaderApplication extends ZLAndroidApplication {

}

那么,我们只能看基类ZLAndroidApplication的实现 

复制代码

public abstract class ZLAndroidApplication extends Application {

    public ZLAndroidApplicationWindow myMainWindow; 

    @Override

    public void onCreate() {

        super.onCreate();

        new ZLSQLiteConfig(this);

        new ZLAndroidImageManager();

        new ZLAndroidLibrary(this);

    }

}

复制代码

它的工作就是

1.初始化sqlite

2.初始化一个图片管理类

3.初始化一个应用程序信息获取的类,如亮度,分辨率,dpi等等 

二 找到启动Activity,在AndroidManifest.xml中找到: 

复制代码

        <activity android:name="org.geometerplus.android.fbreader.FBReader" android:launchMode="singleTask" android:icon="@drawable/fbreader" android:label="FBReader" android:theme="@style/FBReader.Activity" android:configChanges="orientation|keyboardHidden|screenSize">

            <intent-filter>

                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>

            </intent-filter>

复制代码

即启动Activity为FBReader。 

三 下面找出启动之后,书本怎么解析 

在FBReader.java类中,找到onStart()函数 

复制代码

    protected void onStart() {

        super.onStart(); 

        getCollection().bindToService(this, new Runnable() {

            public void run() {

                new Thread() {

                    public void run() {

                        openBook(getIntent(), getPostponedInitAction(), false);

                        myFBReaderApp.getViewWidget().repaint();

                    }

                }.start(); 

                myFBReaderApp.getViewWidget().repaint();

            }

        }); 

        initPluginActions(); 

     // 其他

    }

复制代码

函数中加粗部分,跟踪。。 

复制代码

    private synchronized void openBook(Intent intent, Runnable action, boolean force) {

        Log.i("FBReader" , "FBReader::openBook");

        if (!force && myBook != null) {

            return;

        }

     // 其他 

        myFBReaderApp.openBook(myBook, bookmark, action);

    }

复制代码

继续跟踪上面加粗的函数 

复制代码

    public void openBook(final Book book, final Bookmark bookmark, final Runnable postAction) {

        Log.i("FBReader" , "FBReaderApp::openBook");

        if (book != null || Model == null) {

            runWithMessage("loadingBook", new Runnable() {

                public void run() {

                    openBookInternal(book, bookmark, false);

                    if (book != null) {

                        book.addLabel(Book.READ_LABEL);

                        Collection.saveBook(book, false);

                    }

                }

            }, postAction);

        }

    }

复制代码

继续 

复制代码

    synchronized void openBookInternal(Book book, Bookmark bookmark, boolean force) {

        Log.i("FBReader", "FBReaderApp::openBookInternal");

        if (book == null) { // book为空,获取最近阅读中的第一本书

            book = Collection.getRecentBook(0);

            if (book == null || !book.File.exists()) { // 如果没有阅读历史或者第一个最近阅读的书籍不存在,则打开帮助文件

                book = Collection.getBookByFile(BookUtil.getHelpFile());

            }

            if (book == null) {

                return;

            }

            book.addLabel(Book.READ_LABEL);

            Collection.saveBook(book, false);

        }

        if (!force && Model != null && book.equals(Model.Book)) {

            if (bookmark != null) {

                gotoBookmark(bookmark);

            }

            return;

        } 

        onViewChanged(); 

        storePosition();

        BookTextView.setModel(null);

        FootnoteView.setModel(null);

        clearTextCaches(); 

        Model = null;

        System.gc();

        System.gc();

        try {

            Model = BookModel.createModel(book);

            Collection.saveBook(book, false);

            ZLTextHyphenator.Instance().load(book.getLanguage());

            BookTextView.setModel(Model.getTextModel());

            setBookmarkHighlightings(BookTextView, null);

            BookTextView.gotoPosition(Collection.getStoredPosition(book.getId()));

            if (bookmark == null) {

                setView(BookTextView);

            } else {

                gotoBookmark(bookmark);

            }

            Collection.addBookToRecentList(book);

            final StringBuilder title = new StringBuilder(book.getTitle());

            if (!book.authors().isEmpty()) {

                boolean first = true;

                for (Author a : book.authors()) {

                    title.append(first ? " (" : ", ");

                    title.append(a.DisplayName);

                    first = false;

                }

                title.append(")");

            }

            setTitle(title.toString());

        } catch (BookReadingException e) {

            processException(e);

        } 

        getViewWidget().reset();

        getViewWidget().repaint();

    }

复制代码

 createModel函数如下: 

复制代码

    public static BookModel createModel(Book book) throws BookReadingException {

        final FormatPlugin plugin = book.getPlugin(); // 根据book获取Plugin,需要知道怎么获取Plugin的可以跟踪进去看看 

        System.err.println("using plugin: " + plugin.supportedFileType() + "/" + plugin.type()); 

        final BookModel model;

        switch (plugin.type()) { // 根据Plugin类型,选择用底层的Model还是选择Java层的Model

            case NATIVE:

                model = new NativeBookModel(book);

                break;

            case JAVA:

                model = new JavaBookModel(book);

                break;

            default:

                throw new BookReadingException("unknownPluginType", plugin.type().toString(), null);

        } 

        plugin.readModel(model); // 这里调用ReadModel

        return model;

    }

复制代码

这里强调下,java层木有txt的Plugin,所以我选择一个epub文件来继续在java层跟踪具体实现。 

    @Override

    public void readModel(BookModel model) throws BookReadingException {

        Log.i("FBReader" , "OEBPlugin::readModel");

        model.Book.File.setCached(true);

        new OEBBookReader(model).readBook(getOpfFile(model.Book.File));

    }

这里重头戏来了。 

OEBBookReader.java中的readBook函数如下 

复制代码

    void readBook(ZLFile file) throws BookReadingException {

        Log.i("FBReader", " OEBBookReader::readBook:ZLFile fileName = " + file.getShortName());

        myFilePrefix = MiscUtil.htmlDirectoryPrefix(file); 

     // 清理缓存之类

        myIdToHref.clear();

        myHtmlFileNames.clear();

        myNCXTOCFileName = null;

        myTourTOC.clear();

        myGuideTOC.clear();

        myState = READ_NONE; 

        try {

            read(file); // 这里标记为第一步,以epub随遇而安为例子,这里打开的是/mnt/sdcard/Download/随遇而安.epub:tencent/content.opf

        } catch (IOException e) {

            throw new BookReadingException(e, file);

        } 

        myModelReader.setMainTextModel();

        myModelReader.pushKind(FBTextKind.REGULAR); 

        int count = 0;

        for (String name : myHtmlFileNames) { // 所有章节对应的文件名

            final ZLFile xhtmlFile = ZLFile.createFileByPath(myFilePrefix + name);

            if (xhtmlFile == null || !xhtmlFile.exists()) {

                continue;

            } 

            Log.i("FBReader", " xhtmlFile = " + xhtmlFile.getLongName()); 

            if (count++ == 0 && xhtmlFile.getPath().equals(myCoverFileName)) {

                continue;

            }

            final XHTMLReader reader = new XHTMLReader(myModelReader, myFileNumbers);

            final String referenceName = reader.getFileAlias(MiscUtil.archiveEntryName(xhtmlFile.getPath())); 

            myModelReader.addHyperlinkLabel(referenceName);

            myTOCLabels.put(referenceName, myModelReader.Model.BookTextModel.getParagraphsNumber());

            try {

                reader.readFile(xhtmlFile, referenceName + '#'); // 这里定义为第二步,解析每个章节的内容,第二部最终还是会去调用parser.doIt();

            } catch (IOException e) {

                throw new BookReadingException(e, xhtmlFile);

            }

            myModelReader.insertEndOfSectionParagraph();

        } 

        generateTOC();

    }

复制代码

 先跟踪第一步的代码 

     public void read(ZLFile file) throws IOException {

        ZLXMLProcessor.read(this, file);

    }

    public static void read(ZLXMLReader xmlReader, ZLFile file) throws IOException {

        read(xmlReader, file, 65536);// 一次性读取64K

    }

复制代码

    public static void read(ZLXMLReader xmlReader, ZLFile file, int bufferSize) throws IOException {

        InputStream stream = file.getInputStream(); // 这里打开文件读取数据流啊

        try {

            read(xmlReader, stream, bufferSize);

        } finally {

            try {

                stream.close();

            } catch (IOException e) {

            }

        }

    }

复制代码

复制代码

    public static void read(ZLXMLReader xmlReader, InputStream stream, int bufferSize) throws IOException {

        ZLXMLParser parser = null;

        try {

            parser = new ZLXMLParser(xmlReader, stream, bufferSize);

            xmlReader.startDocumentHandler();

            parser.doIt();// 解析啊,这里就是读取xml文件的内容啊

            xmlReader.endDocumentHandler();

        } finally {

            if (parser != null) {

                parser.finish();

            }

        }

    }

复制代码

 到这里,第一步算是解析完成了 

我们再看看第一步解析出来的数据到哪里去了 

在ZLXMLParser中 

复制代码

    void doIt() throws IOException { 

                        case TEXT:

                            while (true) {

                                switch (buffer[++i]) {

                                    case '<':

                                        if (i > startPosition) {

                                            xmlReader.characterDataHandlerFinal(buffer, startPosition, i - startPosition);

                                        }

                                        state = LANGLE;

                                        break mainSwitchLabel;

                                    case '&':

                                        if (i > startPosition) {

                                            xmlReader.characterDataHandler(buffer, startPosition, i - startPosition);

                                        }

                                        savedState = TEXT;

                                        state = ENTITY_REF;

                                        startPosition = i + 1;

                                        break mainSwitchLabel;

                                }

                            }

                    }

                }

            }

    }

复制代码

看到加粗函数了没? 

 跟踪进去啦! 

    public void characterDataHandlerFinal(char[] ch, int start, int length) {

        characterDataHandler(ch, start, length);

    }

在XHTMLReader中的characterDataHandler函数 

复制代码

    public void characterDataHandler(char[] data, int start, int len) { 

     if (len > 0) {

            if (myInsideBody && !myModelReader.paragraphIsOpen()) {

                myModelReader.beginParagraph();

            }

            myModelReader.addData(data, start, len, false);

        }

    }

复制代码

在BookReader中 

复制代码

    public final void addData(char[] data, int offset, int length, boolean direct) {

        if (!myTextParagraphExists || length == 0) {

            return;

        }

        if (!myInsideTitle && !mySectionContainsRegularContents) {

            while (length > 0 && Character.isWhitespace(data[offset])) {

                --length;

                ++offset;

            }

            if (length == 0) {

                return;

            }

        } 

        myTextParagraphIsNonEmpty = true; 

        if (direct && myTextBufferLength == 0 && !myInsideTitle) {

            myCurrentTextModel.addText(data, offset, length);

        } else {

            final int oldLength = myTextBufferLength;

            final int newLength = oldLength + length;

            if (myTextBuffer.length < newLength) {

                myTextBuffer = ZLArrayUtils.createCopy(myTextBuffer, oldLength, newLength);

            }

            System.arraycopy(data, offset, myTextBuffer, oldLength, length);

            myTextBufferLength = newLength;

            if (myInsideTitle) {

                addContentsData(myTextBuffer, oldLength, length);

            }

        }

        if (!myInsideTitle) {

            mySectionContainsRegularContents = true;

        }

    }

复制代码

到此为止,解析出来的数据添加到BookReader的myCurrentTextModel中,或者是添加到缓存myContentsBuffer中 

原文地址:
http://www.cnblogs.com/deagle/articles/3262289.html