FBReaderv1.8.2启动,阅读流程,及显示研究

一.在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

 

posted @ 2013-08-16 16:42  狼哥2  阅读(931)  评论(0编辑  收藏  举报