xUtils3是目前比较流行的开源项目,因为较原xUtils版本改动较大源码作者干脆另立山头,在Github上建立了新的版本库。xUtils3对6.0版本支持更好,而且删除了不少不常用的功能模块,具体请到官方地址了解详情。
xUtils3可以分成四个部分:视图注入、数据库、网络、图像;本文主要针对数据库模块,分析在数据库模块中使用到的重要的类型数据,数据属于模块的静态组成部分,限于篇幅限制,关于动态流程的分析会在以后的博文继续整理。
官方网站的xUtils3是基于AndroidStudio,我把其中的数据库部分提炼出来整理成Eclipse版本的示例代码,可在http://download.csdn.net/detail/klpchan/9397440下载示例代码,稍加整理后的结构如下:
包结构和原代码结构基本相同:
项目 | 价格 |
---|---|
com.xutils.klpsample | 客户端sample代码 |
org.xutils.commonutils | 通用工具类包 |
org.xutils.db | 接口包,客户端直接调用 |
org.xutils.db.annotation | 注解包 |
org.xutils.db.converter | 对象类型与数据库类型转换包 |
org.xutils.db.sqlite | 数据库信息组件包 |
org.xutils.db.table | 表实体和列实体及其工具包 |
org.xutils.ex | 异常类包 |
下面结合示例整理出几种该数据库模块的重要数据结构。
DbManager$DaoConfig
DaoConfig是DbManager的内部类,顾名思义,其代表的就是配置信息,当用户(客户端)想要去创建一个自定义数据库时,配置数据是要考虑的第一个重要元素,查看下DaoConfig的类视图
可以看出用户可以通过该配置类来设置数据库名称、版本、事务允许开关、更新监听器及存放目录,Sample代码通过如下方式使用
private DbManager initDaoConfig() {
DbManager.DaoConfig daoConfig = new DbManager.DaoConfig()
.setDbName("testklpdb")
.setAllowTransaction(true)
.setDbDir(new File("/sdcard"))
.setDbVersion(1)
.setDbUpgradeListener(new DbManager.DbUpgradeListener() {
@Override
public void onUpgrade(DbManager db, int oldVersion, int newVersion) {
// TODO: ...
// db.addColumn(...);
// db.dropTable(...);
// ...
}
});
DbManager db = XutilDBEnv.getDb(daoConfig);
return db;
}
生成的DaoConfig作为DbManager的重要参数,用于后续的数据库创建中。
DbManager&DbManagerImpl
这个DbManager是暴露给用户的直接接口,用户对于数据库的CRUD操作都可以通过该接口实现,DbManagerImpl是基于该接口的实现类,一个DbManagerImpl就像一个句柄一样,完成针对一个DbConfig的具体操作。通过检查该实现类的Public方法可以看到其暴露的接口属性
如果仅仅为了使用该数据库工具,看到这里就可以结束了,DbManagerImpl就像其类名一样尽职尽责,把用户可以使用的大部分操作都提供了,所以在客户端的代码里,基本充斥的就是该实现类的公共方法,但是对开源项目的学习不能停留在仅仅会用的阶段,继续往下走。
DbManagerImpl.daoMap
从该对象的定义可以看出,这是一个以DaoConfig对象为key、DbManagerImp对象为value的HashMap,由于是静态的,说明该对象描述的是全局配置,换句话说,一个DaoConfig对应唯一的实现类,如果用户想要新建一个数据库并对其进行操作,就要在该Map添加一个新的映射项。
仍然以上面建立的DaoConfig为例,可以查看到daoMap的内容如下
可以看到这个daoMap含有1个有效映射,由于Hashmap并不是按照添加顺序线性排列,这一项HashMapEntry在table中排在第四位,key是配置类,value是接口实现类,检查该变量内容可以看到具体映射值
进一步的,也可以观察一下DaoConfig的内容正如上面代码配置:
columnType_columnConverter_map
这个映射表是在对象类型与数据库类型转换包中,作为一个静态映射表,这是一个key是基本及特定类型,value是converter的全局表。这里需要解释下,xUtils3把数据类型分成两种,一种是正常在代码中使用的基本类型如int、boolean及其包装类型,这些本文称为代码类型;另一种是在数据库中实际存储的类型,称为数据库类型。
之所以分成这两类,是由于数据库存储类型限制造成的,安卓中使用的sqlite是种轻量级的数据库,目前仅支持INTEGER、TEXT、REAL、BLOG、NULL等数据类型,很多基本的代码类型如int、string可以直接存储,但是对于如boolean型、由于数据库不允许存储true、false,只能把boolean转换成INTEGER支持的0或1来表示,char、date类型同样需要转换成INTEGER。
converter就是完成这类作用,columnType_columnConverter_map就是这样以代码类型为key、对应converter为value的静态数据结构。
当开始配合和创建数据库时,可以看到该对象的静态初始化结果
该映射表在ColumnConverterFactory装载时完成了19个映射项的创建,映射项内容如下
可以看到这些基本及包装类型以及Date都对应有各自的转换类,这样用户就可以把这些基本类型通过转换类完成对数据库的各项操作准备。
tableMap
这个一个以数据库#类名为key,以TableEntity为value的映射表,xUtils使用两个结构简单封装良好的实体类作为表示表和列,表使用的是TableEntity,列是columEntity,这两个实体及帮助类放在org.xutils.db.table包中,每个tableEntity中都有一个colum列映射表,表示的是在该表中所有列的集合。
举个例子,本文示例代码使用的是xUtils源码中的Parent作为原始对象,代码如下
@Table(name = "parent")
public class Parent {
@Column(name = "id", isId = true)
private int id;
@Column(name = "name")
public String name;
@Column(name = "email")
private String email;
@Column(name = "isAdmin")
private boolean isAdmin;
@Column(name = "time")
private Date time;
@Column(name = "date")
private java.sql.Date date;
... set及get方法'''
tableMap是一个表示表关系的映射表,ORM实现了从Parent对象到Parent表的直接映射,所以tableMap是一个以数据名#类名为key,tableEntity为value的映射关系图,这样的好处是能够实现对tableEntity的直接管理,以本文为例,Sample代码完成后的tableMap如图所示
分析下tableEntity的类简图可以发现,每个tableEntity表示的是一张表,所以含有这个表里所有的columnEntity,所以其成员变量里含有一个Final的columnMap,而tableMap表示的是对应不同类的表,如Parent、Children,每一种类型对应一个tableEntity,其tableMap不仅仅隶属于特定示例,所以设计成Static的。columnMap由于是类似的结构关系,如下
不再单独分析。
SqlInfo
这个类的结构很简单,包含两个成员变量,sql和bindArgs。SqlInfo用来表示执行实际操作时的sql语句对象,sqlBuilder是对其进行组装的工具类,仍然以上述的Parent类举例,当用户执行对一个Parent对象的插入操作时:
可以看到sql表示执行的含有通配符的sql语句,该sql语句由sqlBuilder组装完成。bindArgs是一个ArrayList,bindArgs是可以单体sql语句中通配符的参数列表,该列表是个KeyValue组成的list,整体的结构如下图
bindArgs中的keyValueList由12个对象组成,其中包括5个有效对象和7个空对象
查看这个List每项的内容,可以发现如下
这个BindArgs正式我们要绑定的数据的kv值,sqlBuilder通过把这个list组装成sql的参数,替代通配符形成最终的插入语句。
小结
本文整理了xUtils3开源项目数据库模块中使用到的几种重要数据结构,仅是针对数据进行静态分析,并没有列出动态流程, 关于业务逻辑会在以后的博文整理,同时如果在后续发现有遗漏的其它该模块重要数据,会在本文中添加。