2019独角兽企业重金招聘Python工程师标准>>>

第三章、获取书籍信息

在第一章与第二章中我们将精力集中在了主线程上,介绍了主线程是如何控制一个进度条的显示和消失,并通过解析资源文件在进度条上显示合适的文字。

从这一章节开始,我们会将精力转到子线程上。本章将介绍后台运行的子线程获取包括文件路径在内等书籍信息的流程。

本章涉及的核心类包括FBReaderApp类、SQLiteBooksDatabase类、Book类、BooksDatabase类、FileInfoSet类

子线程运行的代码其实就是FBReaderApp类initWindow方法中定义的Runnable类中的内容。

正常情况下,因为是第一次进入程序,book变量会是null,代码就会调用getHelpFile方法。然后把帮助文件显示出来。帮助文件是一个格式为fb2的文件,并不是我们常用的epub格式。

为了介绍epub的处理流程,我们就不从默认的处理fb2格式的帮助文件流程入手了,而是假设我们上一次有阅读过一个epub文件,这样Library类的getRecentBook方法就会找到上一次阅读过的epub文件。

我这里选取的用来测试的epub文件是《三体I 地球往事》,权当是向大刘致敬。(这个epub只用作测试,请大家支持正版,多看上有三体合集的购买地址,我自己买的就是这个合集)

回到代码上来,因为参数myArg0都是null,所以book变量也就是null。接下来我们就会进入到Library类的getRecentBook方法。

LibrarygetRecentBook方法:

这个方法会调用SQLiteBooksDatabase类的loadRecentBookId方法

    SQLiteBooksDatabaseloadRecentBookId方法

loadRecentBookId方法其实就是运行了一句sql语句,这句sql语句会从book_index表中取出book_id的值。

看到这句sql语句,我们很自然得就会想去寻找初始化整个Sqlite数据库的代码所在的位置。对sql数据初始化的代码就是SQLiteBooksDatabase类的构造函数


        SQLiteBooksDatabase类构造函数

SQLiteBooksDatabase 类的构造函数是在 FBReader 类中的 createApplication 方法中被调用的。

createApplication方法则是被FBReader的父类ZLAndroidActivity中的onCreate方法调用。

还记得我们在第一章一开始就有说过:“进入到FBReader类,此时首先触发的是FBReader类的父类ZLAndroidActivity中的onCreate方法。”所以,在程序刚刚开始运行的时候sqlite的数据库就被创建了。

好了,现在我们再来详细介绍下SQLiteBooksDatabase类的构造函数。

openOrCreateDatabase方法就是新建或打开一个books.db的数据库。看到这段代码,我们可以知道每个运行过FBReader程序的手机上都会有一个books.db数据库。那么这个数据库究竟是在哪里呢?数据具体在什么地方其实是否是有openOrCreateDatabase方法的第一个参数决定的。如果这个参数是一个绝对路径,那么数据库就会建立到这个路径里面去;如果这个参数是一个相对路径,那么数据库就会建立到程序默认的文件夹里面去。代码中,openOrCreateDatabase方法第一个参数就是使用了相对路径,所以数据库建立程序默认的文件夹里面的。一般来说,数据库比较小,那么方法在程序的默认的文件夹里面是没有问题的。但如果数据库比较大的话,那么就要考虑是否需要放置到sd卡里面去了。

接下来我们去寻找下FBReader的默认文件夹。

一般来说,安装到手机上的程序都会安装到/data/datad的目录下。要找到这个目录,你的手机必须是已经root过的。现在,我们不妨来找一下这个数据库。

在cmd里面通过adb shell命令(安装完sdk,要记得把platform-tools的路径加到环境变量里面去,否则adb命令就不能运行了)和su命令(没有root的话,就没有su命令),然后通过cd /data/data进入文件夹

所有的安装到手机上的程序一般都会安装到/data/datad的目录下,但是这个目录下的文件夹非常得多,FBReader具体是哪个文件夹呢?

其实FBReader文件夹的名字是由AndroidManifest.xml里面的package属性决定的。这个属性的值是什么,FBReader所在的文件夹名字是什么。

我们现在就可以进入这个文件夹,数据库就是在这个文件夹下的databases文件夹下了

我们可以sqlite3 books.db的命令直接进入数据库查看。

进入数据库之后,使用.tables的命令查看下数据库里面到底有哪些表

但是,使用windows的命令行查看books.db会有字符集的问题。sqlite默认的字符集是UTF-8,我们可以用pragma encoding命令查看默认的字符集。

但是windows的命令行却是GBK的字符集,这样一来数据库里面的中文都会是乱码。

为了避免字符集的问题,建议大家可以使用可视化工具来查看sqlite数据库。我使用的是navicat for sqlite,下载地址是http://download.csdn.net/download/zar19901007/6417605

继续回来说数据库,从我们可以从navicat for sqlite看到表还不少,初始状态下这些表肯定都是没有的,都需要代码创建出来的。而完成创建工作的就是SQLiteBooksDatabase类的migrate方法。

        SQLiteBooksDatabasemigrate方法

进入到migrate方法里面,一眼就能看到一个我们第一章中曾经遇到果断的UIUtil类wait方法。这个方法的作用就是在屏幕上显示一个显示等待的进度条,然后从从资源文件中找出特定的字符串,填充到进度条里面去。具体的代码大家可以去查看第一章的内容。

createTables方法负责创建表,创建索引之类的事情则是由一系列的updateTablesX方法来完成了。

回到FBReaderApp类getRecentBook方法:

    BookgetById方法

这个方法会从RecentBooks这张表里面返回book_id,然后会调用Book类的getById方法利用这个book_id去获得书籍的详细信息。
     

Book类的getById方法会调用到SQLiteBooksDatabase的loadBook方法

loadBook方法从Books这张表里面取出书籍的相关信息

接着,loadBook方法调用了BooksDatabase类createBook方法

BooksDatabase类createBook方法首先调用了FileInfoSet类的构造方法,然后又递归得调用了其本身,我们一个一个来看。

FileInfoSet类构造函数

这个构造函数里面有两个方法,分别是SQLiteBooksDatabase类的loadFileInfos方法和FileInfoSet类load方法。

SQLiteBooksDatabase类的loadFileInfos方法会进入一个while循环,这个循环不断得获得file_id对应的parent_id,一直到parent_id为null。


        

代码会针对file_id为57和64的项目代码会调用BooksDatabase类的createFileInfo方法,新建一个FileInfo类(此时FileInfo类的构造函数中的parent参数为null)。

创建出来的FileInfo类被加入到了infos变量所指向的ArrayList中

在while循环之后,代码再利用for循环,从infos变量里面依次把元素取出来,重新调用一遍createFileInfo方法,这一次新建FileInfo类是parent参数就不是null了。新建的FileInfo类最后又被放回infos变量所指向的ArrayList中

代码跳出SQLiteBooksDatabase类的loadFileInfos方法后就会进入FileInfoSet类load方法,这个方法更新了myInfosByPair、myInfosById两个属性。

        BooksDatabasecreateBook方法:

我们之前说过BooksDatabase 类的 createBook 方法会不断递归得调用自身,直到getFile 方法返回null时,代码才会跳出这个递归流程。

首先调用了 FileInfoSet 类的 getFile 方法,这个方法就是从刚刚更新过的 myInfosById 属性里面根据 fileId ,取出对应的 FileInfo 类。

再根据FileInfo类的信息会作为参数被FileInfoSet类的另一个getFile方法。这个方法利用了递归,只要FileInfo的parent属性不是null,递归就会继续。

在这个递归中,会两次调用ZLFile类的createFile方法。

第一次进入createFile方法的时候,第一个参数是null,会建立一个ZLPhysicalFile类,代表/storage/emulated/0/Ebook这个文件夹

第二次进入createFile方法的时候,参数是刚刚建立的ZLPhysicalFile类,此时会建立一个新的ZLPhysicalFile类,这个新的ZLPhysicalFile类将代表epub文件

注意,新建的ZLPhysicalFile类构造函数的参数会是epub文件的完整路径:“/storage/emulated/0/Ebook/三体1《地球往事》.epub”。构造函数会利用这个完整路径创建一个ZLPhysicalFile类。正因这里设置了File类,所以才能在getInputStream方法中返回FileInputStream类。

另外,ZLPhysicalFile类的构造函数调用了ZLFile类的init方法。这个方法设定了myExtension属性,这个属性在第六章“epub文件处理 -- 解析 container文件与.opf文件”中会被用到。

当FileInfoSet类的getFile方法跳出时,返回的是第二次建立的ZLPhysicalFile类。这个ZLPhysicalFile类将作为参数被BooksDatabase类的createBook方法调用。

最终,createBook类返回了一个新创建的Book类。

到这里为止,Library类的getRecentBook方法的流程就走完了,程序获取了book变量指向的Book类。代码以这个类为参数,调用了FBReaderApp类的openBookInternal方法。从这个方法开始,我们就开始对epub文件处理流程了。

转载于:https://my.oschina.net/u/938986/blog/335585

第三章、获取书籍信息相关推荐

  1. 第三章 SQL错误信息

    文章目录 第三章 SQL错误信息 `SQLCODE` `0`和`100` `SQLCODE -400` 检索`SQL`消息文本 第三章 SQL错误信息 下表列出了SQL数字错误代码及其错误消息.这些代 ...

  2. 计算机中的表示方法,计算机应用基础第三章计算机中信息的表示方法

    <计算机应用基础第三章计算机中信息的表示方法>由会员分享,可在线阅读,更多相关<计算机应用基础第三章计算机中信息的表示方法(17页珍藏版)>请在人人文库网上搜索. 1.第第三三 ...

  3. 手把手教你做音乐播放器(三)获取音乐信息

    第3节 获取音乐信息 在"视频播放器"的开发过程当中,我们已经学会了如何获取视频文件的信息: 定义一个视频信息的数据结构VideoItem: 自定义一个AnsycTask,在它的工 ...

  4. 【JAVA】通过ISBN一键获取书籍信息

    package api;import java.util.Vector;import javax.swing.JOptionPane;import net.sf.json.JSONArray; imp ...

  5. 由ISBN自动获取书籍信息——下载可用

    首先需要安装依赖环境,因为代码运行的时候会用到org.apache.http 顺便放一个net.sf.json的依赖包 整理这篇博客的目的是网上的代码有的缺一个类,有的依赖库没给,所以在学的时候费了一 ...

  6. java录入会员信息_Java编程语言基础 第三章 实现会员信息录入功能

    package cn.save; import java.util.Scanner; public class Dome31 { public static void main(String[] ar ...

  7. Java编程语言基础 第三章 实现会员信息录入功能

    package cn.save; import java.util.Scanner; public class Dome31 { public static void main(String[] ar ...

  8. java录入会员信息_Java编程语言基础 第三章 实现会员信息录入功能

    package cn.save;java import java.util.Scanner;input public class Dome31 { public static void main(St ...

  9. java 获取方法_Java 反射理解(三)-- Java获取方法信息

    Java 反射理解(三)-- Java获取方法信息 基本的数据类型.void关键字,都存在类类型. 举例如下: public class ClassDemo2 { public static void ...

  10. C# 通过豆瓣网络编程API获取图书信息

    这篇文章主要是关于如何通过豆瓣API获取信息的书籍,起初,我看到了原来的想法的内容是"C# 网络编程之网页简单下载实现"中通过HttpWebResponse类下载源代码,再通过正則 ...

最新文章

  1. Python知识图谱
  2. 超经典解释什么叫网关
  3. 开源Asp.Net Core小型社区系统
  4. 运营管理整改报告范文_整改报告 反馈问题整改报告范文精选5篇
  5. Linux设备驱动模型3——platform平台总线工作原理
  6. linux下java转储线程_Java线程转储prio值与linux上的真实线程优先级不对应?
  7. 安装SQL2012数据库步骤
  8. css怎么让div旋转不改变形状,旋转任意角度 如何让div旋转一定的角度
  9. 版本为2.5的OpenMP规范中的编译制导指令汇总
  10. ECS之System系统
  11. visual basic对文件夹下的excel执行批量删除行操作
  12. 下载 针式PKM V9.08 版
  13. python-面试通关宝典
  14. 电动自动吞吐式IC卡RFID读写器EMV模块HX150进卡命令
  15. 三阶金字塔魔方还原 - 3步无公式
  16. kaggle:Quora Insincere Questions Classification
  17. python淘宝cookies抢购_Python爬虫利用cookie抓取淘宝商品比价
  18. python瀑布图怎么做_用Matplotlib模拟原始瀑布图
  19. C++中的同名二义性和路径二义性
  20. 实现App跳转到应用商店

热门文章

  1. java web教室管理系统_“真香”教程,455集全套java视频教程,自己拿走去学习吧...
  2. c++生成随机数_C 语言产生随机数的方法
  3. 帆软图表切换接口和图标轮播接口
  4. esxi 需要整合 空间不足_太炫酷了!10月微信新花样!微信情侣空间怎么设置如何弄微信情侣空间在哪里开...
  5. 如何过滤freebayes得到原始vcf文件
  6. linux 打包 压缩
  7. 老生长谈的$.extend()方法
  8. iOS 本地自动打包工具
  9. CentOS 6.5下安装MySQL后重置root密码方法
  10. C#语言课程11月11日