Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 如何將Android數據庫操作通用化(三)

如何將Android數據庫操作通用化(三)

編輯:關於Android編程

概述 悠悠綠水傍林侵日落觀山四望回 幽林古寺孤明月冷井寒泉碧映台 鷗飛滿浦漁舟泛鶴伴閒亭仙客來 游徑踏花煙上走流溪遠棹一篷開

這裡寫圖片描述

概述

一個不小心都寫了三篇了,也不知道大家還看得懂不?如果看不懂最好給我留個言,我好下一次改正。

接著上次的說,准備工作都已經做好了,現在咱們就要開始著手解決阻擋Android數據庫操作通用化的五個問題了。

我們先回顧一下問題: 問題1:表名的獲取 問題2:如何將實體中的數據,按照對應關系導入到數據庫中 問題3:明確實體中主鍵是誰?獲取到主鍵中封裝的值 問題4:如何將數據庫中表的列的數據,按照對應關系,封裝到實體中 問題5:實體的對象創建

悠悠綠水傍林侵,日落觀山四望回。

問題當然是一個一個解決,這樣才有效率,那麼第一個問題來了:表名如何獲取

通常情況下,解決一個問題時,都會以一個方法或者函數開始,這次也不例外,我們先給一個殼子:

/** 問題一:表名的獲取 **/
public String getTableName() {
    return null;
}

一切充滿了希望,也顯得那麼自然。現在我們就要開始思考一些關於如何獲取表名的問題了。

在實際開發中,每一個數據庫表,都會對應著一個具體的實體。就好像news表對應著News類。看看它們,是不是名字好相似?只不過一個是首字母大寫,另一個是全小寫。於是我們心底這麼想,如果我們能夠通過“實體”拿到表名就好了

既然有了路走走看,就知道走的通還是走不通了。

我們可以提出兩個方案: ① 如果能夠獲取到實體,那麼我們就能夠獲取到實體的簡單名稱,然後只需要將首字母小寫就是表名了。但是,這樣的缺點也很明顯,這要求數據庫定義表的名稱和實體的名稱基本一致,這樣就會導致我們定義的實體名稱收到限制。例如:定義了news表,那麼對應的實體就只能是News了。 ② 利用注解,這樣就可以讓實體的名稱和數據庫表的名稱之間的關系脫離,兩者互不干涉。缺點也是顯而易見,編碼難度增加,(嘿嘿),不過誰叫咱們是有經驗的開發人員,就選這種了。

如果有同學注解遺忘掉了,或者還不是很清晰,可以參看我的這篇文章:www.2cto.com

幽林古寺孤明月,冷井寒泉碧映台。

明確了道路,一路向前就可以了。

接下來就要使用到注解和反射什麼的了!!是不是有點小激動~哈哈~

接下來的任務,就是給News實體類增加一個注解了,增加注解的目的則是,將數據庫表和對應實體之間的關系確定下來。請看代碼:

// 注解的作用:將數據庫表和對應的實體確定下來。
@TableName(DBHelper.TABLE_NEWS_NAME)
public class News {
    private int id;
    private String title;
    private String summary;
}

看起來像模像樣的,但是@TableName(DBHelper.TABLE_NEWS_NAME)這句是什麼? 誰能告訴我?

這句就是我們寫的注解了,但是,此時我們還沒有創建出來,但是不要緊,如果你使用的是Eclipse,請選中這行Ctrl+1,就可以自動創建了,這麼高大上,是不是被震到了!↖(^ω^)↗。請看具體的TableName代碼:

/**
 * 制定了實體和數據庫中表的對應關系
 */
@Target(ElementType.TYPE) // 指定放置的位置
@Retention(RetentionPolicy.RUNTIME) // 指定存活時間
public @interface TableName {
    /**
     * 數據庫中的表名,此處可以存放值
     */
    String value();
}

一切都是這麼簡單明了,讓人心曠神怡。現在,注解已經創建好,實體上的注解也已經添加完畢,並且傳入了表名。接下來在getTableName方法中,繼續填寫代碼就好了。

獲取表名依舊分為兩步: ① 獲取到對象的實體 - 這個是問題五 ② 獲取實體頭上的注解,依據value的設置值,確定操作的表。

在偽代碼的第一步是獲取到對象的實體,經過查看,這個恰好是第五個問題,我們先放著,寫一個空方法來代表。

/**
 * 問題五:實體對象的創建
 */
private M getInstance() {
    return null;
}

具體的getTableName()方法代碼如下所示:

public String getTableName() {

    // 偽代碼:
    // ① 問題五:獲取到對象的實體
    M m = getInstance();
    // ② 獲取實體頭上的注解,依據value的設置值,確定操作的數據庫表
    // 需要注意的,想要在“運行時”獲取到注解的信息,給注解設置存活時間。
    TableName tableName = m.getClass().getAnnotation(TableName.class); // annotationType 注解的類型
    // 為了安全起見,判斷注解的合法性;合法則返回value值
    if (tableName != null) {
        return tableName.value();
    }
    return null;
}

有了這個方法,BaseDaoSupport中的delete方法也就可以寫出來了,依舊很簡單,請看代碼:

@Override
public int delete(Serializable id) {
    return db.delete(getTableName(), DBHelper.TABLE_ID + =?, new String[] { id.toString() });
}

小結:其實呢,在表名的獲取中,我們就是利用注解去解決了一個事,表和實體是一一對應的,它們之間的對應關系是什麼。(TableName)

鷗飛滿浦漁舟泛,鶴伴閒亭仙客來。

是時候表演真正的技術了!!(╰_╯)#

接下來該解決第二個問題了,如何將實體中的數據,按照對應關系導入到數據庫中。

回想一下第一個問題的解決,其實就是利用注解解決了,表和實體之間的對應關系。以此類推,第二個問題也是要求將實體中的數據,按照對應關系導入到數據庫中。一樣的思路,繼續往下延續,可以再為實體的字段一個注解,來體現和數據庫表中列的對應關系。請看代碼:

/**
 * 制定了實體的子對岸和數據庫表中列的對應關系
 */
@Target(ElementType.FIELD) // 指定放置的位置
@Retention(RetentionPolicy.RUNTIME) // 指定存活時間
public @interface Column {
    String value();
}

只要字段上有這個注解的,肯定是和數據庫表中的列有對應關系,接下來為實體的字段添加相應的注解,並傳入列名。請看代碼:

// 注解的作用:將數據庫表和對應的實體確定下來。
@TableName(DBHelper.TABLE_NEWS_NAME)
public class News {

    // 指定了實體和數據庫中表的對應關系
    @Column(DBHelper.TABLE_ID)
    private int id;

    @Column(DBHelper.TABLE_NEWS_TITLE)
    private String title;

    @Column(DBHelper.TABLE_NEWS_SUMMARY)
    private String summary;
}

准備工作已經做好了,接下來就要填寫insert中的代碼了,此處新建了一個fillColumn(M m, ContentValues values)方法,把實體M字段值和字段上Column(XXX)注解中傳入的列名,用values.put(key,value)方法填入到valeus中,以便insert中填寫數據。代碼如下:

@Override
public long insert(M m) {
    ContentValues values = new ContentValues();

    // m代表數據源,vlaues是數據導入的目標
    fillColumn(m, values);

    return db.insert(getTableName(), null, values);
}

代碼很簡單,關鍵在於fillColumn(m, values);的數據填充。通過使用反射技術,獲取到M實例的所有字段集合,再依次拿到每個字段的值和每個字段注解的值,並填充到values中,請看代碼:

/**
 * 問題二:如何將實體中的數據,按照對應關系導入到數據庫中
 * 
 * @param m 數據源
 * @param values 是數據導入的目標
 */
public void fillColumn(M m, ContentValues values) {

    // 獲取m上所有的字段
    Field[] fields = m.getClass().getDeclaredFields();

    for (Field field : fields) {
        // 設置訪問權限
        field.setAccessible(true);
        // 獲取字段頭上的注解
        Column column = field.getAnnotation(Column.class);
        if (column != null) {
            try {
                String key = column.value(); // 獲取注解中,指定的列名
                String value = field.get(m).toString(); // 獲取字段值
                // 填寫數據
                values.put(key, value);
            } catch (IllegalArgumentException e) {
                throw new RuntimeException(字段不屬於m實例);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(沒有訪問字段域的權限);
            }
        }
    }
}

總結:只要掌握了思路和方法,整潔、清晰的代碼,寫起來也不是那麼困難。

游徑踏花煙上走,流溪遠棹一篷開。

人生不相見,動如參與商.
今夕復何夕,共此燈燭光.
少壯能幾時,鬓發各已蒼.
訪舊半為鬼,驚呼熱中腸.
焉知二十載,重上君子堂.
昔別君未婚,兒女忽成行……

這裡寫圖片描述

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved