Sqliteを利用する その2

2011/03/23

具体的に実装してみる。

構成

(1) 各アクティビティファイル データモデルファイル、DB等のメイン処理

(2) DatabaseHepler -> SQLiteOpenHelper SQLiteOpenHelper を継承し、DB接続、テーブル管理等の基本処理

(3) SettingDao データモデルに関する、SELECT、INSERT、UPDATE等を実行

(4) Setting データモデル

XCode では CoreData でDBマッピング、管理機能が搭載されているが、Android ではSQLを実際に記述したりと、ちょっと手続きが増える。

DatabaseHepler

コンストラクタでDB接続と、SQLiteDatabase クラスのインスタンスを取得することができる。

DBが存在しない場合は onCreate() が呼ばれるので、onCreate() でスキーマを作成する。 ここでDBを扱った人なら問題ないとは思うが、各テーブルには rowid のようにIDフィールドを追加する事が推奨されている。

またDBバージョンが異なる場合は、onUpgrade() が呼ばれるので、これを利用して管理する。 マイグレートの管理はバージョン番号を使ってやるのか?効率よく管理する方法は、ちょっと不明です。

[java] import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper;

public class DatabaseHelper extends SQLiteOpenHelper {

private static final String DATABASE_NAME = "Selector.db";
private static final int DATABASE_VERSION = 1;

public DatabaseHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL("CREATE TABLE IF NOT EXISTS settings (" +
            "rowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
            " is_active INTEGER, " +
            " name STRING" +
            ")"
            );
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS settings");
    onCreate(db);
}

} [/java]

モデルファイル DAO

setter、getter でデータモデルを作成する。

[java] public class Setting { private long rowid; private boolean isActive; private String name;

//getter
public long getRowid() {
    return rowid;
}

public String getName() {
    return name;
}

public boolean getIsActive() {
    return isActive;
}

//setter
public void setRowid(long rowid) {
    this.rowid = rowid;
}

public void setName(String name) {
    this.name = name;
}

public void setIsActive(boolean isActive) {
    this.isActive = isActive;
}

} [/java]

DAOファイルには、DBカラムを定義し、SELECT、INSERT、UPDATE、DELETE 等のSQL処理や、モデルデータ(ここではSetting)にマッピングをする。

[java] import java.util.ArrayList; import java.util.List;

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

public class SettingDao { private static final String TABLE_NAME = "settings";

private static final String COLUMN_ID = "rowid";
private static final String COLUMN_IS_ACTIVE = "is_active";
private static final String COLUMN_NAME = "name";


private static final String[] COLUMNS = {
                                COLUMN_ID,
                                COLUMN_IS_ACTIVE,
                                COLUMN_NAME
                                };

private SQLiteDatabase db;

public SettingDao(SQLiteDatabase db) {
    this.db = db;
}

    //入力
public long insert(Setting setting) {
    ContentValues values = new ContentValues();
    values.put(COLUMN_IS_ACTIVE, setting.getIsActive());
    values.put(COLUMN_NAME, setting.getName());
    return db.insert(TABLE_NAME, null, values);
}

    //更新
public int update(Setting setting) {
    ContentValues values = new ContentValues();
    values.put(COLUMN_IS_ACTIVE, setting.getIsActive());
    values.put(COLUMN_NAME, setting.getName());
    String where = "rowid = " + setting.getRowid();
    return db.update(TABLE_NAME, values, where, null);
}

    //全取得
public List<Setting> fetchAll() {
    List<Setting> values = new ArrayList<Setting>();
    Cursor cursor = db.query(TABLE_NAME, COLUMNS, null, null, null, null, COLUMN_CREATED_AT);
    while (cursor.moveToNext()) {
        Setting setting = new Setting();
        setting.setRowid(cursor.getInt(0));
        setting.setIsActive(isBooleanForInt(cursor.getInt(1)));
        setting.setName(cursor.getString(2));
        values.add(setting);
    }
    return values;
}

    //取得
public Setting fetch(long rowid) {
    String where = "rowid = " + rowid;
    Cursor cursor = db.query(TABLE_NAME, COLUMNS, where, null, null, null, null);
    while (cursor.moveToNext()) {
        Setting setting = new Setting();
        setting.setRowid(cursor.getInt(0));
        setting.setIsActive(isBooleanForInt(cursor.getInt(1)));
        setting.setName(cursor.getString(2));
        return setting;
    }
    return null;
}

    //削除
public int delete(int rowid) {
    String where = "rowid = " + rowid;
    return db.delete(TABLE_NAME, where, null);
}


private boolean isBooleanForInt(int value) {
    return (value == 1);
}

} [/java] DBとモデルデータのマッピングは Cursor を使って Itarate している。 ただ、Cursorからデータを取得するのにインデックスを利用するのはちょっと怖い気がする。 (他にやり方があるかも?) boolean の扱いはこの方法でいいのか定かではないが、差し当たり。

アクティビティでDB操作する

実際に、アクティビティでDBを操作してみる。

■ListViewに表示する [java] private void loadSetting() { loadDeviceStatus();

    DatabaseHelper databaseHelper = new DatabaseHelper(this);
    SQLiteDatabase db = databaseHelper.getReadableDatabase();

    SettingDao settingDao = new SettingDao(db);
    settings = settingDao.fetchAll();
    db.close();

    ListView listView = (ListView) findViewById(R.id.list);
    SettingListAdapter adapter = new SettingListAdapter(this, R.layout.setting_list_item, settings);
    listView.setAdapter(adapter); 
}

[/java] リスト表示に関しては、「ListViewのカスタマイズ」等を参照。

■データ入力する [java] public void save() { EditText nameEditText = (EditText) findViewById(R.id.nameEditText); ToggleButton activeButton = (ToggleButton) findViewById(R.id.activeButton);

    DatabaseHelper databaseHelper = new DatabaseHelper(this);
    SQLiteDatabase db = databaseHelper.getWritableDatabase();   

    SettingDao settingDao = new SettingDao(db);
    Setting setting = new Setting();
    setting.setName(nameEditText.getText().toString());
    setting.setIsActive(activeButton.isChecked());
    settingDao.insert(setting);

    db.close();
}

[/java]