iT邦幫忙

DAY 14
2

以「寶寶聯絡簿」為例,適合 Android 初學者的學習筆記系列 第 14

寶寶生活記錄 App (Day14 Database 2)

昨天我們簡單說明了如何利用 SQLiteOpenHelper 幫我們建立/管理資料庫,今天會繼續介紹 SQLiteDatabase 這個類別 [1],它可以幫助我們新增/刪除/更新/搜尋資料庫內的資料。筆者在昨天所建立的 lincyu.babylog.db 這個 package 下另外新增了兩個檔案:Baby.java 和 BabyDB.java。

Baby.java 的內容相當單純,其實就是建立一個寶寶類別,讓我們可以產生寶寶物件:

package lincyu.babylog.db;

public class Baby {

    public static final int GENDER_UNKNOWN = 0;
    public static final int GENDER_MALE = 1;
    public static final int GENDER_FEMALE = 2;

    public int babyid;

    public String name;
    public String nickname;
    public String headshot;
    public long birthday;
    public int gender;

	Baby(int babyid, String name, String nickname, String headshot,
         long birthday, int gender) {

        this.babyid = babyid;
        this.name = name;
        this.nickname = nickname;
        this.headshot = headshot;
        this.birthday = birthday;
        this.gender = gender;
	}

	public Baby() {

        babyid = -1;
        name = "";
        nickname = "";
        headshot = "";
        birthday = 0;
        gender = GENDER_UNKNOWN;
	}

    @Override
    public String toString() {
        int namelength = name.length();
        int nicknamelength = nickname.length();

        if (namelength == 0 && nicknamelength == 0) {
            return "";
        } else if (namelength == 0 && nicknamelength != 0) {
            return nickname;
        } else if (namelength != 0 && nicknamelength == 0) {
            return name;
        }
        return nickname + " (" + name + ")";
    }
}

相信這個檔案應該不需要筆者說明了。我們現在來討論 BabyDB.java,其內容如下所示:

package lincyu.babylog.db;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import java.util.ArrayList;

public class BabyDB {

    private static final String BABYID = "_babyid";
    private static final String NAME = "_name";
    private static final String NICKNAME = "_nickname";
    private static final String BIRTHDAY = "_birthday";
    private static final String GENDER = "_gender";
    private static final String HEADSHOT = "_headshot";

    static final String BABY_TABLE = "babytable";
    static final String CREATE_BABY_TABLE = "create table " +
            BABY_TABLE + "(" +
            BABYID + " INTEGER PRIMARY KEY " +
            "AUTOINCREMENT DEFAULT 1 , " +
            NAME + ", " +
            NICKNAME + ", " +
            BIRTHDAY + ", " +
            GENDER + ", " +
            HEADSHOT + ");";

    public synchronized static void addBaby(Context context, Baby baby) {
        addBaby(context, baby.babyid, baby.name, baby.nickname, baby.headshot,
                baby.birthday, baby.gender);
    }

	public synchronized static void addBaby(Context context, int babyid,
            String name, String nickname, String headshot,
            long birthday, int gender) {
		
		DBOpenHelper dbHelper = new DBOpenHelper(context);
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		
		ContentValues cv = new ContentValues();
		
		cv.put(NAME, name);
		cv.put(NICKNAME, nickname);
        cv.put(HEADSHOT, headshot);
        cv.put(BIRTHDAY, birthday);
        cv.put(GENDER, gender);

		if (babyid == -1) { // New Record
			db.insert(BABY_TABLE, null, cv);
		} else { // Existing Record
			db.update(BABY_TABLE, cv, BABYID + "=" + babyid, null);
		}
		db.close();
	}

    public synchronized static void removeBaby(Context context, int babyid) {

        DBOpenHelper dbHelper = new DBOpenHelper(context);
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        db.delete(BABY_TABLE, BABYID + "=" + babyid, null);
        db.close();
    }

    public synchronized static ArrayList<Baby> getAllBabies(Context context) {
        ArrayList<Baby> babylist = new ArrayList<Baby>();

        DBOpenHelper dbHelper = new DBOpenHelper(context);
        SQLiteDatabase db = dbHelper.getWritableDatabase();

        // Cursor c = db.rawQuery("select * from " + BABY_TABLE + ";", null);
        Cursor c = db.query(BABY_TABLE, null, null, null, null, null, null);

        getRecordsKernel(c, babylist);
        c.close();
        db.close();
        return babylist;
    }

    public synchronized static Baby getBabyById(Context context, int babyid) {

        DBOpenHelper dbHelper = new DBOpenHelper(context);
        SQLiteDatabase db = dbHelper.getWritableDatabase();

        Cursor c = db.query(BABY_TABLE, null, BABYID + "=" + babyid, null, null, null, null);
        Baby baby = new Baby();
        if (c.getCount() == 1) {
            c.moveToFirst();
            baby = db2record(c);
        }
        c.close();
        db.close();
        return baby;
    }


	private static void getRecordsKernel(Cursor c, ArrayList<Baby> babylist) {
		c.moveToFirst();
		for (int i = 0; i < c.getCount(); i++) {
			Baby baby = db2record(c);
			babylist.add(baby);
			c.moveToNext();
		}
	}
	
	private static Baby db2record(Cursor c) {
		
		int babyid = -1;
		
		try {
			babyid = c.getInt(c.getColumnIndex(BABYID));
		} catch (Exception e) {
			babyid = -1;
		}
		String name = null;
		try {
			name = c.getString(c.getColumnIndex(NAME));
		} catch (Exception e) {
			name = "";
		}
        String nickname = null;
        try {
            nickname = c.getString(c.getColumnIndex(NICKNAME));
        } catch (Exception e) {
            nickname = "";
        }
        String headshot = null;
        try {
            headshot = c.getString(c.getColumnIndex(HEADSHOT));
        } catch (Exception e) {
            headshot = "";
        }
		long birthday = 0;
		try {
			birthday = c.getLong(c.getColumnIndex(BIRTHDAY));
		} catch (Exception e) {
			birthday = 0;
		}
		int gender = 0;
		try {
			gender = c.getInt(c.getColumnIndex(GENDER));
		} catch (Exception e) {
			gender = Baby.GENDER_UNKNOWN;
		}
		Baby baby = new Baby(babyid, name, nickname, headshot,
                birthday, gender);
		return baby;
	}
}

首先程式定義了一個字串常數 CREATE_BABY_TABLE,熟悉 SQL 語法的讀者可能已經看出常數值是一個 SQL 語法,目的是建立一個新表格 (Table),讀者是否還記得昨天介紹的 DBOpenHelper.java,onCreate 方法內有這麼一行:

db.execSQL(BabyDB.CREATE_BABY_TABLE);

其中 db 是 SQLiteDatabase 物件,也就是今天的重點,SQLiteDatabase 類別的 execSQL 方法可讓我們執行 Non-query SQL 敘述,如 insert, update, delete, alter table, create table, drop table 等,例如昨天筆者有提到我們可能會在 onUpgrade 裡加上如下的敘述:「db.execSQL("alter table " + BabyDB.BABY_TABLE + " add column " + BabyDB.MOTHERNAME + ";");」,然而對於 insert, update, delete 這 3 個 SQL 敘述,SQLiteDatabase 另外提供了 insert, update, delete 等 Methods,BabyDB.java 就是直接使用這些 Methods。

BabyDB.java 的 addBaby 這個方法示範了insert 和 update 的用法,首先 ,我們產生一個 DBOpenHelper 物件,DBOpenHelper 昨天已經介紹過了,會幫我們檢查資料庫是否存在、是否需要更新,接著呼叫 SQLiteOpenHelper 類別的 getWritableDatabase 方法取得一個 SQLiteDatabase 物件,有了這個 SQLiteDatabase 物件,我們就可以執行相關的 SQL 敘述。

程式是利用 ContentValues [2] 來準備 insert/update 的資料,資料是採用 Key-Value 的方式放入,其中 Key 是表格的欄位名稱 (Column name),Value 則是要 insert/update 的值,這裡有一點要提醒讀者,由於 _babyid 這個欄位是 PRIMARY KEY 且設定成會自動加一,因此我們不需要手動設定其值。

接著,筆者設定成若呼叫 addBaby 時 babyid 的值為 -1 代表要插入一筆新記錄,因此呼叫 SQLiteDatabase 物件的 insert,insert 需要 3 個參數,第 1 個參數是表格 (Table)名稱,第 2 個參數是處理 ContentValues 為空的情況 (詳細說明請參考 [1]),此處填上 null 即可,第 3 個參數則是代入前面產生的 ContentValues 物件。若呼叫 addBaby 時 babyid 的值不是 -1 代表要更新一筆已經存在的記錄 (Record),update 的第 1 個參數是表格名稱,第 2 個參數 ContentValues 物件,第 3 和第 4 個參數是跟 SQL 的 where 敘述相關,第 4 個參數是在第 3 個參數有包含「?」的情況下才會使用到,下面是一個範例:

String[] args = { "Bill", “bill@fake.mail.com” };

db.update(“TABLE_NAME", cv, "name=? and email=?", args);

在我們自己的程式碼中,由於第 3 個參數直接將 babyid 代入,沒有用問號,因此第 4 個參數填上 null 即可。而第 3 個參數所代表的意義是我們要更新的記錄是 _babyid 值為 babyid 的那一筆記錄。最後程式呼叫 close 將資料庫關起來,至此就完成了 insert 和 update 的說明。

接著我們來看 removeBaby 這個 Method,delete 的第 2 和第 3 個參數就是跟 update 的第 3 和第 4 個參數一樣,分別是 whereClause 和 whereArgs,而 removeBaby 內的寫法代表我們要刪除某個特定 babyid 的記錄,其餘的敘述就應該不需贅述了。

今天我們集中在 Non-query SQL 敘述的介紹,SQLiteDatabase 物件的 execSQL 方法可執行 Non-query SQL 敘述,SQLiteDatabase 還特別針對 insert/update/delete 提供了特定的 Methods。明天我們會介紹 SQLiteDatabase 針對跟查詢 (Query) 相關的 SQL 敘述所提供的 Methods。

參考資料

[1] SQLiteDatabase | Android Developers, http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html

[2] ContentValues | Android Developers, http://developer.android.com/reference/android/content/ContentValues.html


上一篇
寶寶生活記錄 App (Day13 Database 1)
下一篇
寶寶生活記錄 App (Day15 Database 3)
系列文
以「寶寶聯絡簿」為例,適合 Android 初學者的學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言