文档章节

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

charlessun
 charlessun
发布于 2014/08/07 18:25
字数 1317
阅读 96
收藏 0
一.在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

charlessun
粉丝 48
博文 57
码字总数 42432
作品 0
闸北
程序员
私信 提问
移动设备阅读体验

一直想对移动设备阅读体验进行较为完整的研究和学习,但内容太多,涉及到非常多的传统平面设计知识,目前仅初步地完整字体部分。完整的研究框架包括: 1.界面版式设计的方法。常用的栅格分割...

junwong
2012/03/01
420
1
Android M Launcher3主流程源码浅析

背景 关于Launcher是啥的问题我想这里就没必要再强调了。由于一些原因迫使最近开始需要研究一下Launcher3源码,为了不再像以前那么傻逼(研究Settings等代码没作笔记),故这里赶紧将阶段性的...

aweiloveandroid
2017/06/29
0
0
DARPA人工智能技术研究情况一览

来源:一体化指挥调度国家工程实验室、高端装备发展研究中心 摘要:20世纪60年代初,DARPA(当时为ARPA)开始介入自主技术研究,并很快成为该领域的主要研究机构。DARPA意识到,人工智能可以...

人工智能学家
2018/09/26
0
0
DARPA宣布未来五年将投资20亿美元开发下一波人工智能技术

来源:国防科技信息网 作者:丁宏 中国船舶工业综合技术经济研究院 美国DARPA近日宣布,计划在未来5年内投资20亿美元用于开发下一波人工智能技术,寻求情境推理能力等技术的突破,使其有能力...

人工智能学家
2018/09/10
0
0
研究生(包括博士)选题与开题报告撰写

来源:科学网博客 作者:张铁峰 编辑:学妹 新入学和刚开始从事研究的研究生(开题报告)首先要进行选题,选题是开始研究前必须完成的工作。一般导师会根据自己的专业背景和项目需求给学生划...

Airship
2015/03/05
184
0

没有更多内容

加载失败,请刷新页面

加载更多

排序––快速排序(二)

根据排序––快速排序(一)的描述,现准备写一个快速排序的主体框架: 1、首先需要设置一个枢轴元素即setPivot(int i); 2、然后需要与枢轴元素进行比较即int comparePivot(int j); 3、最后...

FAT_mt
31分钟前
3
0
mysql概览

学习知识,首先要有一个总体的认识。以下为mysql概览 1-架构图 2-Detail csdn |简书 | 头条 | SegmentFault 思否 | 掘金 | 开源中国 |

程序员深夜写bug
今天
9
0
golang微服务框架go-micro 入门笔记2.2 micro工具之微应用利器micro web

micro web micro 功能非常强大,本文将详细阐述micro web 命令行的功能 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go-micro环境, golang微服务框架...

非正式解决方案
今天
6
0
前端——使用base64编码在页面嵌入图片

因为页面中插入一个图片都要写明图片的路径——相对路径或者绝对路径。而除了具体的网站图片的图片地址,如果是在自己电脑文件夹里的图片,当我们的HTML文件在别人电脑上打开的时候图片则由于...

被毒打的程序猿
今天
8
0
Flutter 系列之Dart语言概述

Dart语言与其他语言究竟有什么不同呢?在已有的编程语言经验的基础上,我们该如何快速上手呢?本篇文章从编程语言中最重要的组成部分,也就是基础语法与类型变量出发,一起来学习Dart吧 一、...

過愙
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部