先膜拜一下郭神,话说郭神可以带我飞不?
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.关闭事务
今天就扯这么多,再膜拜一下大神!
欲知详情,请听下回讲述!