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中


 

你可能感兴趣的:(FBReaderv1.8.2启动,阅读流程,及显示研究)