先膜拜一下郭神,话说郭神可以带我飞不?
1.上回说到context,这回我们接着说,配置完AndroidManifest.xml,下面就要开始建表了,那bean中的内容又是如何跟数据库关联起来的呢?上篇博客说到郭哥使用SAX解析xml,其中SAX解析的格式是不变的,主要区别在handle,我们继续看handle的处理代码:
@Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (LitePalParser.NODE_DB_NAME.equalsIgnoreCase(localName)) { for (int i = 0; i < attributes.getLength(); i++) { if (LitePalParser.ATTR_VALUE.equalsIgnoreCase(attributes.getLocalName(i))) { litePalAttr.setDbName(attributes.getValue(i).trim()); } } } else if (LitePalParser.NODE_VERSION.equalsIgnoreCase(localName)) { for (int i = 0; i < attributes.getLength(); i++) { if (LitePalParser.ATTR_VALUE.equalsIgnoreCase(attributes.getLocalName(i))) { litePalAttr.setVersion(Integer.parseInt(attributes.getValue(i).trim())); } } } else if (LitePalParser.NODE_MAPPING.equalsIgnoreCase(localName)) { for (int i = 0; i < attributes.getLength(); i++) { if (LitePalParser.ATTR_CLASS.equalsIgnoreCase(attributes.getLocalName(i))) { litePalAttr.addClassName(attributes.getValue(i).trim()); } } } else if (LitePalParser.NODE_CASES.equalsIgnoreCase(localName)) { for (int i = 0; i < attributes.getLength(); i++) { if (LitePalParser.ATTR_VALUE.equalsIgnoreCase(attributes.getLocalName(i))) { litePalAttr.setCases(attributes.getValue(i).trim()); } } } }
首先获得数据库名,放到litePalAttr的DBName中,同理vision和case也一样,这里的class时间bean中是实体了.
/** * Add a class name into the current mapping model list. * * @param className * Full package class name. */ void addClassName(String className) { getClassNames().add(className); }
获得实体的属性值加入到className中
public List<String> getClassNames() { if (classNames == null) { classNames = new ArrayList<String>(); classNames.add("org.litepal.model.Table_Schema"); } else if (classNames.isEmpty()) { classNames.add("org.litepal.model.Table_Schema"); } return classNames; }
这里实体与数据库如何关联的差不多就明确了,主要还是SAX解析XML,给对应的属性赋值,上篇博客有提到是否可以建多个数据库,理论上是可以的,但是现在的版本暂时不支持,他没有对lite标签进行区分.估计郭哥以后的版本会添加这个功能!
2.说到数据库升级,郭神真是太屌了,改一个数据全搞定,这也体现了LitePal的巧妙之处,个人猜测郭神是根据version值的大小进行更新,旧版本号小于新版本号时更新,这只是个人猜测,还是去看一看郭哥的源码比较靠谱
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Generator.upgrade(db); SharedUtil.updateVersion(newVersion); }
首先郭哥继承了SQLiteOpenHelper,重写了onCreate方法和onUpgrade方法,这里不多说,继续看onUpgrade里面的实现方法
static void upgrade(SQLiteDatabase db) { drop(db); create(db, false); updateAssociations(db); upgradeTables(db); addAssociation(db, false); }
这里简单说一下,欲知详情,请看郭哥源码
1.删除数据库
2.创建数据库
3.更新数据库表,移除外键和中间链表
4.更新所有的数据库中的表
5.添加关联
更新完表之后,继续更新版本号
public static void updateVersion(int newVersion) { SharedPreferences.Editor sEditor = LitePalApplication.getContext() .getSharedPreferences(LITEPAL_PREPS, Context.MODE_PRIVATE).edit(); sEditor.putInt(VERSION, newVersion); sEditor.commit(); }
郭哥这里使用SharedPreferences直接把版本号存在了本地
3.LitePal存储数据
郭哥说:”LitePal进行表管理操作时不需要这些实体类有任何的继承结构,当时为了简单起见就没有写。但是进行CRUD操作时就不行了,LitePal要求所有的实体类都要继承自DataSupport这个类,因此这里我们就要把继承结构给加上才行。”DataSupport主要是数据库和实体类的桥梁,郭哥在DataSupport中给出了一个实例:
* public class Person extends DataSupport { * private int id; * private String name; * private int age; * }
实体类Person会自动去映射person表,就相当于:
* CREATE TABLE person ( * id integer primary key autoincrement, * age integer, * name text * );
LitePal的保存主要是通过save()方法实现,当然save()方法里面调用了saveThrows(),你也可以直接调用saveThrows();下面看一下save()的源码:
public synchronized boolean save() { try { saveThrows(); return true; } catch (Exception e) { e.printStackTrace(); return false; } }
这里调用saveThrows()主要就是返回成功与否了,没什么要解释的,那就直接看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(); } }
1.创建表
2.开启事务
3.调用SaveHandle的onSave方法
void onSave(DataSupport baseObj) throws SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { String className = baseObj.getClassName(); List<Field> supportedFields = getSupportedFields(className); Collection<AssociationsInfo> associationInfos = getAssociationInfo(className); if (!baseObj.isSaved()) { analyzeAssociatedModels(baseObj, associationInfos); doSaveAction(baseObj, supportedFields); analyzeAssociatedModels(baseObj, associationInfos); } else { analyzeAssociatedModels(baseObj, associationInfos); doUpdateAction(baseObj, supportedFields); } }
这里就涉及到关联问题了,一对一,多对一,多对多,根据以前见得实体是否更改,如果更改了就保存,没有更改则只是更新就可以了.这里涉及到的关联关系省略,主要看一下doSaveAction和doUpdateAction
private void doSaveAction(DataSupport baseObj, List<Field> supportedFields) throws SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { ContentValues values = new ContentValues(); beforeSave(baseObj, supportedFields, values); long id = saving(baseObj, values); afterSave(baseObj, supportedFields, id); }
在存值之前先判断其中的值是否发生变化,然后执行saving方法,返回的是id,是不是觉得很眼熟,哈哈,没错,这里执行的插入操作
private long saving(DataSupport baseObj, ContentValues values) { return mDatabase.insert(baseObj.getTableName(), null, values); }
同样的,doUpdateAction和doSaveAction差不多,不在赘述,只贴一下更新时的最终操作:
private void updating(DataSupport baseObj, ContentValues values) { mDatabase.update(baseObj.getTableName(), values, "id = ?", new String[] { String.valueOf(baseObj.getBaseObjId()) }); }4.清除关联数据
5.关闭事务
今天就扯这么多,再膜拜一下大神!
欲知详情,请听下回讲述!