Android学习——涉及意识形态的LitePal源码分析
原创技术博客,请认准Azzssss的原文http://www.cnblogs.com/Azzssss/p/4147704.html。
这两天项目终于上线了,松了一口气,虽然还是很不稳定,见一步走一步吧。反正总算能抽出时间来写博客了。在项目中用到了LitePal,LitePal是什么鬼东西呢?它的Github主页是什么介绍的:“LitePal是一个开源的android库,允许开发者极其方便地去使用sqlite数据库。通过它,你甚至可以不写一行SQL语句来完成大部分的数据库操作,包括创建和更新表,crud操作,聚合函数等等。LitePal的配置同样很简单,5分钟就可以整合进你的项目。”
我第一次知道LitePal是通过郭林的博客,这家伙好牛,我学android起就看他的博客了,郭先生一连写了八篇博客介绍LitePal,相见恨晚啊。这篇博客主要是想深入了解LitePal的源码,如果还没使用过LitePal,建议先移步郭先生的博客,这是他关于LitePal的第一篇博客《Android数据库高手秘籍(零)——前言》。
现在,先看看LitePal的save操作,太简单了,忍不住再次称赞一下。
public class Album extends DataSupport { private String name; private float price; private List<Song> songs = new ArrayList<Song>(); // generated getters and setters. ... } Album album = new Album(); album.setName("album"); album.setPrice(10.99f); album.save();
是不是很简单?想起自己写过的sqlite语句是不是嗷的一声昏过去了?这里我先讲一下大概的思路吧,是这样实现的,每一个实体类都要继承DataSupport这个类,通过反射找到实体类中所有的属性(只能是基本数据类型或者String),通过反射将对象属性的值put到ContentValues里面,然后就调用原生SQLiteDatabase的方法insert进去。当然,这里面还涉及到关联数据的东西,这个有点复杂,稍后分析。
下面我们看看,这个save操作究竟进行了什么,走起~
我们点进去DataSupport的save方法,发现是这样的(我是不是应该画个类图啊)
public synchronized boolean save() { //调用了saveThrows()方法 代码上的注释是这么说的,如果这个是一条新的记录,就会在数据库中create,否则就更新现有的数据。 try { //它怎么区分这条数据是否在已经在数据库中了?答案是根据JavaBean里地id或者_id属性(必须为int类型或者long类型),这是一个约定,如果实体类 saveThrows(); //中有这个属性,这个id的值将会由数据库创建并在调用save方法后自动指派给它(原理我稍后看看),并且判断这个id属性是否有值区分insert和update操作 return true; } catch (Exception e) { e.printStackTrace(); return false; } }
接下来我们看saveThrows()方法
public synchronized void saveThrows() { SQLiteDatabase db = Connector.getDatabase(); //获取数据库 db.beginTransaction(); //这个估计是开启事务?先放着 try { SaveHandler saveHandler = new SaveHandler(db); //这是关键咯 saveHandler.onSave(this); clearAssociatedData(); //不知道这个是什么鬼,清理外键数据啥的 db.setTransactionSuccessful(); } catch (Exception e) { throw new DataSupportException(e.getMessage()); } finally { db.endTransaction(); } }
这里LitePal把储存的操作封装在SaveHandler里面了,其实增删改查的操作还分别封装了DeleteHandler,UpdateHandler,QueryHandler,这四个类继承自DataHandler
SaveHandler的onSave方法是这样的
void onSave(DataSupport baseObj) throws SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
String className = baseObj.getClassName(); //获取类名,例子里就是Album类名,其实调用的就是getClass().getName(); List<Field> supportedFields = getSupportedFields(className); //找出这个实体类中的所有属性,但是只支持基本数据类型和String类型 Collection<AssociationsInfo> associationInfos = getAssociationInfo(className); //这里涉及到关联数据,先不理 if (!baseObj.isSaved()) { //判断模型已经创建与否,也就是说这条数据是否在数据库中了,就一行return baseObjId > 0,所以说实体类的id值不要自己手动去设 analyzeAssociatedModels(baseObj, associationInfos); //关联数据相关,等一下再分析 doSaveAction(baseObj, supportedFields); analyzeAssociatedModels(baseObj, associationInfos); //关联数据相关,等一下再分析 } else { analyzeAssociatedModels(baseObj, associationInfos); //关联数据相关,等一下再分析 doUpdateAction(baseObj, supportedFields); //如果baseObjId不为空,更新 } }
先说一下doSaveAction
private void doSaveAction(DataSupport baseObj, List<Field> supportedFields) throws SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
ContentValues values = new ContentValues(); beforeSave(baseObj, supportedFields, values); //beforeSave 主要功能是通过反射把实体类的数据存入ContentValues,动态地获取数据类型,并调用相 //应的put方法 long id = saving(baseObj, values); //保存数据到表中,并且返回一个long类型的id afterSave(baseObj, supportedFields, id); //afterSave }
现在看看这行代码 long id = saving(baseObj, values); 这里点进去,就发现是调用SQLiteDataBase的insert操作了,之前我们不是把通过反射把ContentValues的数据都put好了吗,接着调用SQLiteDataBase的insert方法,这个nullColumnHack参数是为了防止插入空行,底层数据库不允许插入一个空行
public long insert(String table, String nullColumnHack, ContentValues values)
好了,看看afterSave()方法,插入后的操作
private void afterSave(DataSupport baseObj, List<Field> supportedFields, long id) { throwIfSaveFailed(id); //如果id为-1,抛出异常,插入数据失败 assignIdValue(baseObj, getIdField(supportedFields), id); //指派id给JavaBean,就是那个Album对象 updateAssociatedTableWithFK(baseObj); //更新关联的表,先不要理,关联那块另外说 insertIntermediateJoinTableValue(baseObj, false); //这个也涉及到关联数据,多对多关系下的中间表操作,先放着 }
好像差不多了,SaveHandler里面还有update的方法没提到,还有一小部分关于关联的操作。先吃个夜宵再写。。。。顺便研究一下怎么画类图,还有怎么把博文迁到我的github博客。看到有错别字请给我提醒一下,不谢。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。