FBReader代码分析:创建BookModel时,如何根据Book来得到对应的FormatPlugin?
本篇文章暂时只是本人看代码过程中备忘的记录,未详细的整理,条理不太清晰。
BookModel -> createModel(Book book);
Book -> getPlugin() -> getPlugin(ZLFile) -> 实际由PluginCollection类获取:
PluginCollection -> getPlugin(ZLFile) -> getPlugin(file, FormatPlugin.Type.ANY)
public FormatPlugin getPlugin(ZLFile file, FormatPlugin.Type formatType) {
final FileType fileType = FileTypeCollection.Instance.typeForFile(file);
final FormatPlugin plugin = getPlugin(fileType, formatType);
if (plugin != null && plugin.type() == FormatPlugin.Type.EXTERNAL) {
return file == file.getPhysicalFile() ? plugin : null;
}
return plugin;
}
FileTypeCollection类初始化了所有可接受的文件类型:FileTypeCollection
/**
* 以FileType的Id为Key,FileType为值存储下来
*/
private final TreeMap<String, FileType> myTypes = new TreeMap<String, FileType>();
private FileTypeCollection()
{
addType(new FileTypeFB2());
addType(new FileTypeEpub());
addType(new FileTypeMobipocket());
addType(new FileTypeHtml());
addType(new SimpleFileType("plain text", "txt", MimeType.TYPES_TXT));
addType(new SimpleFileType("RTF", "rtf", MimeType.TYPES_RTF));
addType(new SimpleFileType("PDF", "pdf", MimeType.TYPES_PDF));
addType(new FileTypeDjVu());
addType(new SimpleFileType("ZIP archive", "zip", Collections.singletonList(MimeType.APP_ZIP)));
addType(new SimpleFileType("MS Word document", "doc", MimeType.TYPES_DOC));
}
private void addType(FileType type)
{
myTypes.put(type.Id.toLowerCase(), type);
}
public Collection<FileType> types()
{
return myTypes.values();
}
这些可接受的文件类型集,包括:
FileType | 对应Id | 实际接受的文件后缀(acceptsFile) | mimeTypes |
FileTypeFB2 | fb2 | .fb2、.fb2.zip | application/x-fictionbook、application/x-fictionbook+xml、application/fb2+xml、text/fb2+xml、application/fb2+zip |
FileTypeEpub | ePub | epub、oebzip、opf | application/epub+zip、application/epub |
FileTypeMobipocket | Mobipocket | pdb、prc、mobi、azw3 | application/x-mobipocket-ebook |
FileTypeHtml | HTML | html、htm | text/html、application/html、application/html+htm |
FileTypeDjVu | DjVu | djvu、djv | image/vnd.djvu、image/x-djvu、application/djvu |
SimpleFileType | plain text | txt | text/plain、application/txt |
SimpleFileType | RTF | rtf | application/rtf、text/rtf |
SimpleFileType | application/pdf | ||
SimpleFileType | ZIP archive | zip | application/zip |
SimpleFileType | MS Word document | doc | application/msword、application/doc |
可以根据传入的ZLFile得到该ZLFile所被支持的FileType对象:FileTypeCollection -> typeForFile(ZLFile file)
public FileType typeForFile(ZLFile file)
{
for (FileType type : types()) {
if (type.acceptsFile(file)) {
return type;
}
}
return null;
}
实际获取FormatPlugin的方法PluginCollection -> getPlugin(FileType fileType, FormatPlugin.Type formatType)
public FormatPlugin getPlugin(FileType fileType, FormatPlugin.Type formatType) { if (fileType == null || formatType == null) { return null; } switch (formatType) { case ANY: { FormatPlugin p = getPlugin(fileType, FormatPlugin.Type.NATIVE);// 优先获取Native的FormatPlugin
if (p == null) {// 加载不到时才加载Java的FormatPlugin
p = getPlugin(fileType, FormatPlugin.Type.JAVA);
}
if (p == null) {// 再加载不到时,加载扩展的FormatPlugin
p = getPlugin(fileType, FormatPlugin.Type.EXTERNAL);
}
return p; } default: { final List<FormatPlugin> list = myPlugins.get(formatType); if (list == null) { return null; } for (FormatPlugin p : list) {
// p.supportedFileType()实际返回的是初始化FormatPlugin时传入的myFileType(从表2查看);
// FileType的Id值(从表1查看)将于FormatPlugin的myFileType进行匹配,匹配上了边返回对应的FormatPlugin if (fileType.Id.equalsIgnoreCase(p.supportedFileType())) { return p; } } return null; } } }
1.首先默认进入了ANY,递归再次进入,携带的formatType为FormatPlugin.Type.NATIVE,然后进入的是default。
2.然后得由这个formatType去得到List<FormatPlugin>。现在需要知道myPlugins是怎么来初始化的?
// ======================= 以下代码便是myPlugins的初始化过程=======================
private final Map<FormatPlugin.Type,List<FormatPlugin>> myPlugins =
new HashMap<FormatPlugin.Type,List<FormatPlugin>>();
public static PluginCollection Instance() {
if (ourInstance == null) {
// 这里初始化所有支持的FormatPlugin实例
// 1.MobipocketPlugin -> FormatPlugin.Type.Java
// 2.DjVuPlugin -> FormatPlugin.Type.EXTERNAL
// 3.PDFPlugin -> FormatPlugin.Type.EXTERNAL
ourInstance = new PluginCollection();
// This code can not be moved to constructor because nativePlugins() is a native method
for (NativeFormatPlugin p : ourInstance.nativePlugins()) {
ourInstance.addPlugin(p);
System.err.println("native plugin: " + p);
}
}
return ourInstance;
}
private PluginCollection() {
addPlugin(new MobipocketPlugin());
if (Build.VERSION.SDK_INT >= 8) {
addPlugin(new DjVuPlugin());
addPlugin(new PDFPlugin());
}
}
private void addPlugin(FormatPlugin plugin) {
final FormatPlugin.Type type = plugin.type();
List<FormatPlugin> list = myPlugins.get(type);
if (list == null) {
list = new ArrayList<FormatPlugin>();
myPlugins.put(type, list);
}
list.add(plugin);
}
private void NativeFormatPlugin[] nativePlugins();
myPlugins以FormatPlugin.Type为Key存储了对应FormatPlugin.Type的所有FormatPlugin。
FormatPlugin.Type的所有类型:FormatPlugin -> enum Type:
public enum Type {
ANY,
JAVA,
NATIVE,
EXTERNAL;
};
某FormatPlugin子类 | 该类的myFileType | 其对应父类 | 该类的Type |
BuiltinFormatPlugin(abstract) | FormatPlugin(abstract) | ||
JavaFormatPlugin(abstract) | BuiltinFormatPlugin(abstract) | Type.JAVA | |
NativeFormatPlugin | BuiltinFormatPlugin(abstract) | Type.NATIVE | |
FB2NativePlugin | fb2 | NativeFormatPlugin | Type.NATIVE |
OEBNativePlugin | ePub | NativeFormatPlugin | Type.NATIVE |
MobipocketPlugin | Mobipocket | JavaFormatPlugin(abstract) | Type.JAVA |
ExternalFormatPlugin(abstract) | FormatPlugin(abstract) | Type.EXTERNAL | |
DjVuPlugin | DjVu | ExternalFormatPlugin(abstract) | Type.EXTERNAL |
PDFPlugin | ExternalFormatPlugin(abstract) | Type.EXTERNAL |
打开某一个epub资源 example.epub ,断点进入时,下面是所有FileType的值:
{
djvu=org.geometerplus.zlibrary.core.filetypes.FileTypeDjVu@52ddbe84,
epub=org.geometerplus.zlibrary.core.filetypes.FileTypeEpub@52dda188,
fb2=org.geometerplus.zlibrary.core.filetypes.FileTypeFB2@52dd9fd8,
html=org.geometerplus.zlibrary.core.filetypes.FileTypeHtml@52dda6d0,
mobipocket=org.geometerplus.zlibrary.core.filetypes.FileTypeMobipocket@52dda4e8,
ms word document=SimpleFileType [MS Word document],
pdf=SimpleFileType [PDF],
plain text=SimpleFileType [plain text],
rtf=SimpleFileType [RTF],
zip archive=SimpleFileType [ZIP archive]
}
下面是所有FormatPlugin的值:
可以看出共有六种类型的FormatPlugin当前被支持了。
因此,上面的example.epub资源,其对应的FileType是epub=org.geometerplus.zlibrary.core.filetypes.FileTypeEpub[ePub],FormatPlugin是OEBNativePlugin[ePub]。