FBReader源码分析(四)---数据之源Model分析

hs2933

贡献于2012-12-26

字数:0 关键词: Android开发 移动开发

FFFFBBBBRRRReeeeaaaaddddeeeerrrr源源源源码码码码分分分分析析析析((((四四四四))))------------数数数数据据据据之之之之源源源源MMMMooooddddeeeellll分分分分析析析析 创创创创建建建建时时时时间间间间::::2012/06/15 10:32 更更更更新新新新时时时时间间间间::::2012/06/15 17:06 作作作作 者者者者::::陆再谋(nil) 来来来来 源源源源::::http://sixreader.com 一、万事开头难 正所谓“巧妇难为,无米之炊”。FBReader要想实现能够支持各种文件格式,就需要对来源的数据进 行规整化处理,结构化出自己需要数据。求同存异,抽象出相同的特性为父类,而子类保持各自的特性。 大家可以想象,FBReader打开txt和epub文件,它们本身结构就不一样,但是在界面渲染显示的时 候,发现它们有什么特别的不同。确实是这样的,FBReader要想实现对各种格式的支持,就需要对这些文 件格式的数据进行分析。txt比较简单,都是文本;epub就复杂多了,不但有文本,还有图像,超链接等。 所以,可以认为txt是epub的子集。 FBReader就抽象出一种标识:  也就是上面的接口,FBReader读取txt的话,只要在保存到自己缓存的时候在每段的前面加一个标 签“TEXT"就可以;而epub的话,碰到一段(

),也是用"TEXT"作为标签,而解析的时候碰到了img, 那么保存到自己缓存文件的时候前面就加"IMGE",同理,链接的话就是”CONTROL"等。 所以这个Model的工作就是实现对不同格式的数据,规整出FBReader自定义的结构想要的数据,并且 能保存读取。 二、Model内容数据之-------来源 在第三篇文章中,留了一个Model结构没有详细解析,那么这篇就彻底把Model阐述。  包名:packageorg.geometerplus.fbreader.fbreader; 类名:publicfinalclassFBReaderAppextendsZLApplication 方法:voidopenBookInternal(finalBookbook,finalBookmarkbookmark) 代码: Model=BookModel.createModel(book); 按Ctrl键的同时点击createModel方法(谨记这个操作),就能跟过去,会跑到类BookModel的静态 方法createModel上。 方法:publicstaticBookModelcreateModel(Bookbook) 功能:根据插件,判断出属于那种格式,然后会先判断是否采用本地C生成Model还是用Java生成 Model(简单就这么说咯)----一个是NativeBookModel,一个是PlainBookModel。然后插件 对Model进行初始化。  按Ctrl键同时点击createModel方法里的plugin.readModel(model)函数,跟下去(以后我就直接说 跟某某函数咯)。 好,跑到了抽象类FormatPlugin里的一个抽象方法readModel(BookModel); 查看这个抽象方法在哪里实现的! 按Ctrl+T(一起按)(谨记此操作),会出现如下截图:  发现弹出的提示框中有一个OEBPlugin,那就是epub对readModel方法的实现了。点击提示框中 的“OEBPlugin",看看到底如何实现readModel方法的。 包名:packageorg.geometerplus.fbreader.formats.oeb 类名:publicclassOEBPluginextendsFormatPlugin 方法:publicbooleanreadModel(BookModelmodel)  这段代码会判断生成一个ZLFile的对象,然后model会直接跑到OEBBookReader的构造函数中,初始 一下(没有任何数据),然后用readBook函数来读取数据。 跟readBook(opfFile)方法,跑到(提示一下:因为我的2.0版本修改太多了,所以从这里就就用1.5版 本):  包名:packageorg.geometerplus.fbreader.formats.oeb 类名:classOEBBookReaderextendsZLXMLReaderAdapterimplementsXMLNamespaces 方法:voidreadBook(ZLFilefile)throwsBookReadingException  此函数前面几行代码都是清空数据等操作,但是下面这行就比较关键了:  童鞋们~!按住Ctrl键的同时点击read(file)函数,一直跟read函数下去,会跑到: 包名:packageorg.geometerplus.zlibrary.core.xml 类名:publicabstractclassZLXMLProcessor 方法:publicstaticvoidread(ZLXMLReaderreader,InputStreamstream,intbufferSize) throwsIOException  代码中就有一个传说中解析函数doIt了!小部分截图:  大家看到了,它是一个无传入参数的函数,那么假设读取epub的话,它到底读那个文件什么内容?现 在依然是问号。 所以跑到这里,我们似乎需要去找到它打开的文件是啥,才能知道到如何解析的。  回到类OEBBookReader中,知道readBook(ZLFilefile)中传入了一个ZLFile的对象,我们需要知道它 到底是什么东西。 因为doIt()函数肯定是基于这个对象来知道到打开文件的。 好,我们在readBook(ZLFilefile)中打几个Log,看看到底是什么?  在read(file)前面添加一个Log,运行!可惜没出这条Log!!小宇宙爆发吧~~~····· 想想估计是1.5使用C++的解析,而不是选择用Java,于是跑到如下路径: "jni/NativeFormats/src/format/PluginCollection.cpp的PluginCollection &PluginCollection::Instance()函数,注释掉OEBPlugin插件就OK!重新编译,运行。 于是就出现打印结果:  额,啥情况?肿么是fb.opf呢? 倒退一个函数:  在这里打一个Log,打印结果就是(我打开的文件是nil1.epub,文章可以直接跟我要):  也就是说getOpfFile改变了打开的对象,那为何要把后缀和文件名都变了? 额,这里解释一下,童靴们可以把epub文件的后缀名改为zip,然后解压,打开OPS/fb.opf的文件,你 就知道这个是epub的索引文件。也就是说,你要得到epub的内容,你的从这个文章找到索引信息,然后才 能找到某个章节对应的html.  直接打开fb.opf文件,内容如下:   所以,打开epub的关键就看opf文件!  下面接下来肯定就是读取opf文件,解析出封面对应的html和各个章节对应的html,然后再一一读取这 些文件。 原文:   打印结果:   所以跟我们的分析是吻合的,doIt()函数的工作就是解析了,读完这个文件,基本就已经出了章节结 构。解析xml的过程我们就不叙述了。反正知道doIt()函数中能够把xml解析出对应的数据就OK咯。 那么生成epub的章节在哪里? 在OEBBookReader.java里面的一个startElementHandler函数中,myHtmlFileNames记录了所有的 章节和对应的html文件。 好,说了这么多。章节对应的hmtl终于放到myHtmlFileNames了,接下来就是真正读取html,然后 加载数据到Model了。回到OEBBookReader.java中的函数: voidreadBook(ZLFilefile)throwsBookReadingException(如下截图为部分代码)    myHtmlFileNames中,已经有对应的html文件,接下来就是获取内容,然后添加到缓存,还有保存 到本地文件了。 代码中的reader.readFile(xhtmlFile,referenceName+"#")就是读取各个html了。比如下: 原文:  打印的结果:   同样,doIt()又是一个人在战斗!!! 它会根据html的内容生成对应的数据,放到Model里面去,我们看看它怎么放到Model的。  三、Model内容数据之-------添加内容数据  FBReader中,doIt函数如下部分代码:  其中的xmlReader.characterDataHanlder(data,6,len-8)会把doIt不断解析的数据传给 包名:packageorg.geometerplus.fbreader.formats.xhtml 类名:publicclassXHTMLReaderextendsZLXMLReaderAdapter 方法:publicvoidcharacterDataHandler(char[]data,intstart,intlen) 此方法中最后有一段这样的代码如下:  代码中的myModelReader.addData(data,start,len,false)就是把数据放到Model去了! 跟一下它,publicfinalvoidaddData(char[]data,intoffset,intlength,booleandirect)函数终 究是添加到Model了,如下代码:  哇色!终于看到Model添加数据了。 再跟下去,就会发现 包名:packageorg.geometerplus.zlibrary.text.model 类名:publicfinalclassZLTextWritablePlainModelextendsZLTextPlainModelimplements ZLTextWritableModel 方法:  实现了对数据的添加!同时我们也看到了ZLTextParagraph.Entry.TEXT,也就是本文最开始说的 FBReader添加内容的结构的标签。同样你在这个类里面会发现其他比如添加图像,以及超链接的函数。 四、Model内容数据之-------弱引用缓存和本地存储保存 为了实现快速地找到数据,FBReader对数据结构化后,保存了一份数据在WeakReference数组中,并 且用一个ArrayList把这些内容数组保存起来。同时它也做了一个份数据在本地中。具体代码在跟上面的 addText函数中的getDataBlock(3+length)找到这样一个类!  而实现此接口的是抽象类CachedCharStorage的子类CachedCharStorage,部分代码如下: 抽象类:  子类CachedCharStorage有一个方法实现了保存到本地:    FBReader保存的数据如下:  五、总结 Model的数据就到此了,它从何而来,然后放到何处,在文中已经有所阐述。可能有一些内容,比如解 析xml,解析html然后得出对应想要的结果doIt函数是如何做的?那就又各位自己去研究doIt函数了。 同时,数据虽然已经保存在缓存或者本地,但是如何利用这些数据然后绘制到画布上?将在下一篇中解 释。 ==============================End================================ ========= 转载请说明出处:http://sixreader.com陆再谋(Nil)撰写 联系方式:synwith@163.com QQ:1351231599 QQ2群:233932132   

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享文档获得金币 ] 0 人已下载

下载文档

相关文档