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博客。看到有错别字请给我提醒一下,不谢。

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。