打造android ORM框架opendroid(七)

在上一篇博客《打造android ORM框架opendroid(六)——级联查询》我们讲了OpenDroid最后一块功能查询的实现原理。今天我们将进行OpenDroid一个重头戏,也是本系列博客的最后一篇——数据库升级方案。说道数据库升级,我可是很头疼的, 为什么呢? 因为以前的项目中,根本没有考虑数据库升级方案的问题,就直接drop table了,这样导致的结果就是“以前的数据都消失了”。额。。。 凭空消失确实不是很少的一件事,如果数据不重要还行,重要数据呢? 说消失就消失了? 用户升级了一下软件,结果数据全没了。。。 那是多吊丝的一件事。OpenDroid则提供了一种数据库升级的方案,当然这种方案肯定不是完美的。 肯定还有更好的方案,如果你发现你有好的解决方案,请不吝赐教。好,,下面开始进入正题。首先说说我的方案的原理吧:其实很简单,就是在drop table之前将数据查询出来,并保存到集合中,在创建新表后,尝试去insert数据。原理的思路很简单,以至于我一直认为这种方案太烂了, 可我没有想到更好的结果方案,也就只能先这样了。大家都知道,android的SQLiteOpenHelper类中提供了一个抽象方法onUpgrade()来让用户灵活的定制数据库升级方案, 最简单的方法就是我之前提到直接drop table。既然upgrade的权利掌握在我们手中,那我们何不借onUpgrade()大干一番呢?

先来看看代码:

@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {System.out.println("upgrade database");upgrade(db); }在onUpgrade里除了一句打印,其实真正有用了就一句代码,当然也是调用了我们自定义的一个方法,那么我们就从upgrade()这个方法开始说起:/** * 升级数据库 * @param db 数据库链接 */ private <T extends OpenDroid> void upgrade(SQLiteDatabase db) {try {XmlPullParser pullParser = Xml.newPullParser();InputStream inputStream = DroidApplication.sContext.getAssets().open("open_droid.xml");pullParser.setInput(inputStream, "utf-8");int type = pullParser.getEventType();while(type != XmlPullParser.END_DOCUMENT) {if(type == XmlPullParser.START_TAG) {// 获取mappingif(pullParser.getName().equals(OpenDroidHelper.TAG_MAPPING)) {dumpData(db, pullParser);}}type = pullParser.next();}} catch (Exception e) {e.printStackTrace();}// 执行创建数据库onCreate(db); }7~9行可以看出我们准备去解析open_droid.xml文件了,和我们平时解析一样,使用一个while循环,观察while循环,我们在15~17行获取到了有用的信息,如果当前的tag是mapping的或,我们又去调用了dumpData,这里面XmlPullParser会作为第二个参数传递过去。方法的最后,我们直接调用了重载的onCreate方法去创建新表,当然还有数据的恢复。这个我们稍后分析,接下来我们来看看dumpData方法。/** * 将数据库中的数据转储到程序中 * @param db 数据库连接 * @param pullParser * @throws Exception */ private <T extends OpenDroid> void dumpData(SQLiteDatabase db, XmlPullParser pullParser)throws Exception {Class<OpenDroid> klass = (Class<OpenDroid>) Class.forName(pullParser.getAttributeValue(null, "class"));String tableName = klass.getSimpleName(); // 表名Cursor cursor = db.rawQuery("select * from " + tableName, null);T t;Method m;String methodName;String columnName;// 遍历游标for(cursor.moveToFirst();!cursor.isAfterLast();cursor.moveToNext()) {t = (T) klass.newInstance(); // 通过反射进行实例化final int columnCount = cursor.getColumnCount();for(int i=0;i<columnCount;i++) {columnName = cursor.getColumnName(i); // 获取字段名// try一下,如果没有该字段对应的方法,则消化异常,并继续try {switch (cursor.getType(i)) {case Cursor.FIELD_TYPE_INTEGER:methodName = columnName.equals("_id") ? "setId" :CRUD.getMethodName(cursor.getColumnName(i));m = klass.getMethod(methodName, int.class); // 反射出方法m.invoke(t, cursor.getInt(i)); // 执行方法break;case Cursor.FIELD_TYPE_FLOAT:methodName = CRUD.getMethodName(cursor.getColumnName(i));m = klass.getMethod(methodName, float.class);m.invoke(t, cursor.getFloat(i));break;default:methodName = CRUD.getMethodName(cursor.getColumnName(i));m = klass.getMethod(methodName, String.class);m.invoke(t, cursor.getString(i));break;}} catch (Exception e) {e.printStackTrace();}}mOldData.add(t);}cursor.close();db.execSQL("drop table if exists " + tableName); // 删除旧的数据库 }这个方法很长,而且也很关键,我们的数据库升级方案将在这里终结。第9行,我们通过Class.forName获取了一个Class, 是根据什么映射呢?来看一下我们open_droid.xml文件就一目了然。<open-droid><version value="6" /><name value="school" /><mapping class="org.loader.opendroid.Student" /><mapping class="org.loader.opendroid.Grade" /> </open-droid>这这个xml中,我们就是要通过org.loader.opendroid.Student来映射出一个类。第10行,我们获取了该类的类名,当然也就是我们要操作的表名了,唉? 为什么就一个表呢? 仔细看看这个方法是在哪调用的,我们是在一个循环中调用了,也就是在循环中去遍历xml节点,每次获取到mapping节点,都来调用一下这个方法。11行,我们执行一段select语句,将现在表中所有的数据查询出来,那查询出来的数据我们怎么处理呢?要回答这个问题,我们就得去下面的for循环中找答案。在for循环中,20行,通过反射实例化了上面那个类,为什么要在循环中实例化呢?因为每行数据我们都需要用一个对象来保存。21行,获取了当前行所有列的个数。接下来有一个for循环,这个循环我们是循环的每一行的列,在循环中去取每一列的数据。26行,进入一个switch语句,依照惯例,我们只去分析一个case语句。在第一个case中,如果改列的字段是一个integer类型,28行,我们和之前讲过的一样去拼装一个setter,当然如果是_id的话,我们就直接定义为setId了。30行,反射出这个方法,等待下面去执行。当然31行我们就要去执行这个方法了,我们都知道setter方法是需要参数的,参数当然就是我们查询出来的当前列的数据了。48行,我们将这个对象的实力放入一个集合中。当查询完当前表,这个表就没用了,因为我们已经把数据都保存起来了,所以在51行,将该表删除。至此,我们就把数据从旧版本的数据库中全部查询出来了。接下来我们回到onCreate方法中来看看新表是如果创建的,并且数据是如何恢复的。获致幸福的不二法门是珍视你所拥有的遗忘你所没有的

打造android ORM框架opendroid(七)

相关文章:

你感兴趣的文章:

标签云: