在上一篇博客[《打造android ORM框架opendroid(二)——自動創建數據庫》](http://blog.csdn.net/qibin0506/article/details/42773281)中,我們介紹了opendroid是怎么做到自動幫我們創建好數據庫并通過反射拼湊出創建數據庫的SQL語句,接著上面的博客,今天要來介紹一下opendroid數據庫持久化(也就是insert操作)是怎么一個流程。
廢話不多少,我們馬上進入主題。
...
還記得通過opendroid我們是如何將數據保存到數據庫的嗎? 當時是調用了從OpenDroid類繼承過來的save方法,來回顧一下吧。
~~~
Student?stu?=?new?Student();??
stu.setStuName("亓斌");??
stu.setStuAge(18);??
stu.save();??
~~~
這樣我們就把student的信息保存到了Student表中了,關于Student表是怎么創建的,前面一篇博客中已經介紹過了,今天的重點就是這個save()方法。
按照慣例,我們定位到save()的源碼。
~~~
/**?
?*?插入數據?
?*?@return?最后插入的id?
?*/??
public?long?save()?{??
????try?{??
????????Class?klass?=?(Class)?getClass();??
????????ContentValues?cv?=?new?ContentValues();??
????????generateData(klass,?cv);??
??????????????
????????return?CRUD.insert(klass.getSimpleName(),?cv,?sSqliteDatabase);??
????}?catch?(Exception?e)?{??
????????e.printStackTrace();??
????}??
????return?-1;??
}??
~~~
這個方法還是比較簡單的,只有11行代碼,我們來一句句的分析一下。
首先第7行,通過getClass方法獲取了當前代表當前對象的Class。
接著第8行new了一個ContentValues,相信大家對它肯定再熟悉不過了。
9行,調用了generateData方法,這個方法有兩個參數,第一個是一個Class對象,第7行的時候我們已經獲取了,第二個參數是一個ContentValues,用來保存存放將要插入數據庫的數據。
接著在11行,調用了CRUD類中的insert靜態方法來保存數據,insert方法的第一個參數是要插入的表名,因為我們的表和bean是一一對應的,所以當前類名就是我們要操作的表名,第二個參數是一個SQLiteDatabase對象。
CRUD.insert方法會返回一個long類型的返回值,相信大家已經猜到了,返回值就是我們新插入數據的id。
分析完這個方法,接下來我們就來看看第9行中調用的generateData方法.
~~~
/**?
?*?生成數據?
?*?@param?tableName?要獲取的表名?
?*?@param?values?要獲取的數據?
?*?@throws?NoSuchMethodException?
?*?@throws?IllegalAccessException?
?*?@throws?InvocationTargetException?
?*/??
private?void?generateData(Class?klass,?ContentValues?values)??
10. ????????throws?NoSuchMethodException,?IllegalAccessException,??
????????InvocationTargetException?{??
????Field[]?fields?=?klass.getDeclaredFields();?//?獲取類中的所有字段??
????Method?m;??
????String?fieldName;??
????String?methodName;??
??
????for?(Field?field?:?fields)?{??
????????//?如果是public,則忽略??
????????if?(field.isAccessible())?{??
????????????continue;??
????????}??
??
????????//?獲取字段的類型??
????????Class?fieldType?=?field.getType();??
??
????????fieldName?=?field.getName();?//?獲取字段名稱??
????????//?將字段名稱的首字母大寫,準備拼裝getter(getName)??
????????methodName?=?Character.toUpperCase(fieldName.charAt(0))?+?fieldName.substring(1);??
??
????????//?這里還要判斷一下類型是不是boolean,??
????????//?如果是boolean,?就不是getXXX了,而是isXXX??
????????if?(fieldType?==?Boolean.class?||?fieldType?==?boolean.class)?{??
????????????m?=?klass.getDeclaredMethod("is"?+?methodName);??
????????}?else?{??
????????????m?=?klass.getDeclaredMethod("get"?+?methodName);?//?獲取方法??
????????}??
??
????????//?獲取方法的返回值??
????????Object?value?=?m.invoke(this);??
????????//?對于一些類型不支持。。??
????????//?未找到解決方案??
????????if?(value?==?null)?{??
????????????//?如果是null,則在contentValues里添加一個null??
//??????????values.putNull(fieldName);??
????????????continue;??
????????}??
??
????????//?通過判斷field的類型,向contentValues插入對應的數據??
????????if?(fieldType?==?Integer.class?||?fieldType?==?int.class)?{??
????????????values.put(fieldName,?Integer.parseInt(m.invoke(this).toString()));??
????????}?else?if?(fieldType?==?Boolean.class?||?fieldType?==?boolean.class)?{??
????????????values.put(fieldName,?Boolean.parseBoolean(m.invoke(this).toString()));??
????????}?else?{??
????????????values.put(fieldName,?m.invoke(this).toString());??
????????}??
????}??
}??
~~~
在今天要講解的方法中,這個方法算是最長的了,沒關系,我們一行行的來看。
方法的參數我們在上面已經說明了,這里就不重復了,在方法剛開始,接連不斷的定義了4個變量,第一個變量是我們通過klass獲取到的該類中所有的字段,接下來我們要通過這些字段來獲取要保存的值和字段名。剩下的幾個變量我們在用到的時候再來說。
17行,進入了一個for循環,遍歷的所有的字段,循環中,19~21行,我們依然去判斷該字段是不是public,如果是public,則證明該字段并沒有映射到數據庫中。
24行,獲取了字段的類型,因為在下面我們要通過類型來設置值。
26~28行,我們準備去拼湊getter方法。
接著32~36行,又是一個判斷,主要是為了我們java bean定義的規范,如果是boolean類型的,我們在定義方法的時候難道不是isXXX嗎?
ok,我們通過反射獲取了將要調用的的方法,接下來39行就要通過getter方法來獲取具體的值了。
42~46行是一個敗筆,還未能結果對于沒考慮到的類型的怎么去支持,不過也不影響,常用的類型已經支持了。
49~55行,通過字段的類型,來向ContentValues中保存不同類型的值,可以看到我們使用調用m.invoke方法來執行反射出來的方法。
至此,我們已經將數據都保存進ContentValues中了,接下來就是調用android原生的api代碼,將數據庫保存進數據庫就ok了。
而保存進數據庫肯定就是調用了CRUD.insert方法,趕緊來看看這個方法吧。
~~~
/**?
?*?插入數據?
?*?@param?t?對應的bean?
?*?@param?db?數據庫操作?
?*?@return??最新插入的id?
?*/??
protected?static?long?insert(String?tableName,?ContentValues?cv,?SQLiteDatabase?db)?{??
????long?id?=?db.insert(tableName,?null,?cv);??
????return?id;??
}??
~~~
太幸福了! 只有兩行代碼! 看看吧,我們直接調用了傳過來的SQLiteDatabase的insert方法將數據保存進了數據庫。相信看到這里,大家對save的整個流程應該有了大概的認知。
好,opendroid的數據持久化流程就說到這里,在接下來的博客中我們還會去了解opendroid的其他操作。
opendroid的開源地址:[http://git.oschina.net/qibin/OpenDroid](http://git.oschina.net/qibin/OpenDroid)