標籤:架構 orm opendroid
在上一篇部落格《打造android ORM架構opendroid(二)——自動建立資料庫》中,我們介紹了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<OpenDroid> klass = (Class<OpenDroid>) 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<OpenDroid> klass, ContentValues values)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了,而是isXXXif (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
打造android ORM架構opendroid(三)——持久化資料