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中 


  
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FBReader 是一种快速且高度可定制的电子书阅读器,适用于运行 Android OS 的设备(支持 1.5 或更高版本,建议 2.0 或更高版本)。 FBReader Premium App 的免费版本是标准版本,具有付费版本的所有功能。唯一的区别是 4.99 美元的溢价价格。 如果您已经在免费使用该应用程序,那么价格似乎有点高。 但是,它仍然提供与常规 FBReader 版本的用户所喜欢的相同的快速,简单的信息访问方式。 安卓电子书阅读FBReader 中文多语免费版安卓电子书阅读FBReader 中文多语免费版 FBReader 可用功能 大声朗读(通过 Android 文本语音转换) Google 翻译集成 内置对 PDF 和漫画格式的支持 缩略图库视图 主要电子书格式:ePub(包括 ePub3 的主要功能),PDF,Kindle azw3(mobipocket),fb2(.zip)。 其他受支持的格式:漫画书(CBR / CBZ),RTF,doc(MS Word),HTML,纯文本。 为了帮助您阅读外语,请使用 FBReader 的词典集成来查找单词或短语。您可以从多种外部词典中进行选择。 在 FBReader 中,您可以使用集成的 Google 或 Yandex 转换器翻译句子而无需离开应用程序。 FBReader 支持您的图书馆和/或阅读位置与 FBReader 图书网络(https://books.fbreader.org/)的同步,这是一种基于 Google Drive™ 的云服务。默认情况下,同步是禁用的;要启用和配置它,请使用“首选项”对话框。 FBReader 快速且高度可定制-它可以使用外部 TrueType / OpenType 字体和自定义背景,可以在读取时调节屏幕亮度(沿屏幕左边缘向上/向下滑动手指),并且可以选择不同的昼/夜配色方案。 该阅读器还包括一个浏览器/下载器,用于访问不同的网络电子书目录和商店。包括几个流行的英语,法语,俄语,中文和波兰语库。还支持自定义 OPDS 目录。 或者,您可以手动下载书籍,然后将其保存在设备上的 /sdcard/Books 中。 此外,该阅读器已针对 34 种语言进行了本地化,并包括针对 24 种语言的连字符模式。
主要电子书格式:ePub(包括ePub3的主要功能),PDF,Kindle azw3(mobipocket),fb2(.zip)。其他支持的格式:漫画书(CBR / CBZ),RTF,doc(MS Word),html,plain文本。 升级到这个流行的电子书阅读器的高级版。 此高级版本提供的功能: * Google / Yandex翻译集成 *内置支持PDF和漫画书格式 *缩略图库视图 为了帮助阅读外语,请使用FBReader的字典集成来查找单词或短语。您可以从众多外部词典中进行选择。 在FBReader Premium中,您可以使用集成的Google或Yandex翻译器在不离开应用程序的情况下翻译句子。(警告:此功能的每日使用可能会受到限制。) FBReader支持使用基于Google Drive™的云服务FBReader图书网络(https://books.fbreader.org/)同步您的图书馆和/或阅读位置。默认情况下禁用同步; 要启用和配置它,请使用首选项对话框。 FBReader快速且高度可定制 - 它可以使用外部TrueType / OpenType字体和自定义背景,可以在阅读时调整屏幕亮度(沿着左侧屏幕边缘向上/向下滑动手指),并且可以选择不同的日/夜配色方案。 该阅读器还包括一个浏览器/下载器,用于访问不同的网络电子书目录和商店。包括几个流行的英语,法语,俄语,中文和波兰语库。也支持自定义OPDS目录。 或者,您可以手动下载书籍并将其保存在/ sdcard / Books中的设备上。 此外,该阅读器本地化为34种语言,包括24种语言的连字模式。该应用程序是开源(GPL)。 什么是新的 内置文字转语音模块 文件选择器 新升商店目录 重大内部变化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值