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中