アンドロイドのデータベースについて SQlite
データベースからデータの 読 み 込 み Cursorクラス
Cursorでデータをとってきます // 注 意 定 数 でDatabaseクラスの 中 にあるとします public static final String ID = " id"; public static final String NAME = "_name"; // 例 えばこんなデータベースがあるとして(SQLiteOpenHelperクラスを 継 承 したもの) Database database = new Database(context); //データベースからとってくるカラム final String[] PROJECTION = { Database.ID, Database.NAME ; //データベースからデータをCursorで 取 ってくる Cursor c = database.query( Database.TABLENAME, PROJECTION, null, null, null, null, Database.TABLE_COLUMNS.ID + " ASC" );
CursorをmoveToFirst()を 最 初 にやって movetonext()で 次 のデータへ 進 めます Cursorはイテレータです //カラムは 何 番 目 かをとってくる int idxid = c.getcolumnindex(database.id); int idxname = c.getcolumnindex(database.name); //これを 忘 れると カーソル-1 番 目 から 始 まってエラー c.movetofirst(); if ( c.getcount() > 0 ) //カーソルのデータ 数 取 得 { do { int id = c.getint(idxid); String name = c.getstring(idxname); //なにかの 処 理 while ( c.movetonext() ); //クローズしないとリーク! c.close(); database.close();
>クエリの 発 行 ( SQLiteDatabaseクラス ) //データベースからとってくるカラム final String[] PROJECTION = { Database.ID, Database.NAME ; この 順 番 でCursorに 値 がはいる SQLiteDatabase.query( テーブル 名, カラムの 名 前 が 入 ったString 配 列 ( 上 のPROJECTION), クエリー, SelectionArgs(String 配 列 ), GroupBy, Having, ソート 順 ); SelectionArgsはクエリーのところで ID =? or price =? として String[] selectionargs = { 10, 100 ; を 設 定 すると? のとこが 左 から 順 に 置 き 換 わる ID = 10 or Price = 100 となる 使 わないかも( 汗
>Cursorについて カーソルのインデックス 番 号 0 番 に 戻 す movetofirst() カーソルのインデックス 番 号 を 次 へ 進 める movetonext() カーソルのインデックス 番 号 をNum 番 まで 進 める MoveToPosition( Num ) カーソルのRowの 数 を 得 る(データの 数 ) getcount() カラム 番 号 の 値 をそれぞれの 型 で 受 け 取 る getint( カラム 番 号 ) getstring( カラム 番 号 ) getfloat( カラム 番 号 ) getboolean( カラム 番 号 ) カーソルのカラム 名 から 何 番 目 にアクセスすればいいかを 得 る getcolumnindex( カラムの 名 前 (String) ) カーソルを 閉 じる close()
>DDMSの 画 面 Cursorをクローズしなければ DDMSで 表 示 されます 緑 文 字 (info)なので メモリリークにはなってないかもしれません (OS1.6では 赤 字 (error)でleak found!と 表 示 されていた)
Cursorからデータを 取 ってくるとき インデックスの 番 号 で 取 得 することになります 2 通 りの 方 法 があります 1カラムの 番 号 を 直 接 いれる String name = Cursor.getString(1); 2 最 初 に 一 度 カラムの 番 号 をカラム 名 で 問 い 合 わせておく (Database.Nameはstatic final String Name = _name ;) Int idxname = Cursor.getColumnIndex( Database.Name ); String name = Cursor.getString( idxname ); 結 果 は 同 じですが 1はあとでソースを 見 たときにさっぱりわからない 2がお 勧 めです
Cursorの 中 身 をデバッグなどで 簡 単 に 表 示 したい 場 合 Logクラスを 使 用 すると ログ 出 力 できます DDMSなどで 確 認 できます しかし 自 前 でログ 出 力 を 作 りたくない そんなとき! ログ 出 力 の 際 に Cursorの 中 身 をログ 出 力 してくれる 便 利 なクラス android.database.databaseutils.dumpcursor(cursor); ログ 出 力 の 中 身
Cursorを 自 分 で 作 りたい 場 合 final String[] projection = { "id","color" ; MatrixCursor c = new MatrixCursor(projection); c.addrow( new Object[]{ 1,"blue" ); c.addrow( new Object[]{ 2,"red" ); c.addrow( new Object[]{ 3,"green" ); c.addrow( new Object[]{ 4,"pink" ); c.addrow( new Object[]{ 5,"white" ); MatrixCursorを 使 えば 作 れますが なかなか 用 途 は 思 いつきません( 汗
データベースクラスの 作 り 方 SQLiteOpenHelperクラス
データベースを 操 作 する 前 段 階 として 面 倒 な 問 題 があります データベースのファイルはすでに 存 在 するか ない 場 合 は ファイル 作 成 テーブル 作 成 データベースのバージョンは 同 じか 同 じでないなら アップグレード(テーブル カラムの 追 加 等 ) Cursorでデータの 読 み 出 し
SQLiteOpenHelperクラスはそれをやってくれます public class Database extends SQLiteOpenHelper { public Database(Context context, String name, CursorFactory factory,int version) { super(context, name, factory, version); // name は ファイル 名 (ファイル 名 のみ!ファイルパス 付 は 不 可 ) // factory は 不 明 ( 汗 // version はデータベースバージョン( 自 分 で 決 める) @Override public void oncreate(sqlitedatabase db) { // ファイルがない 場 合 に 呼 ばれる @Override public void onupgrade(sqlitedatabase db, int oldversion, int newversion) { // バージョンが 違 うときに 呼 ばれる
SQLiteOpenHelperを 実 装 したとき データベースのファイルはすでに 存 在 するか oncreate() ない 場 合 は ファイル 作 成 テーブル 作 成 データベースのバージョンは 同 じか OnUpgrade() 同 じでないなら アップグレード(テーブル カラムの 追 加 等 ) Cursorでデータの 読 み 出 し
注 意 点 端 末 内 のデータベースファイルからの 読 み 出 しか メモリ 上 のデータベースしか 操 作 できない data/data/ アプリ / databaseにあるdata.dbを 使 う New Database( context, data.db, null, 1 ); メモリ 上 だけで 使 う New Database( context, null, null, 1 ); OnUpgrade()でアップグレード 処 理 を 書 いても インストールされたときはonCreate()しか 呼 ばれない oncreate()に 最 終 的 なバージョンのテーブル 作 成 などの 処 理 を 書 かないと インストールした 人 はみ んな 開 いた 瞬 間 エラー!
public class Database extends SQLiteOpenHelper { protected SQLiteDatabase mwritable = null; protected SQLiteDatabase mreadable = null; public Database(Context context, String name, CursorFactory factory,int version) { super(context, name, factory, version); mwritable = getwritabledatabase(); mreadable = getreadabledatabase(); // 以 下 はSQLiteHelperクラスには 用 意 されていない 自 作 です public Cursor query(string table, String[] columns, String selection, String[] selectionargs, String groupby, String having, String orderby) { Cursor c = mreadable.query(table, columns, selection, selectionargs, groupby, having, orderby); c.movetofirst(); return c; public void update(string table, ContentValues values, String whereclause) { mwritable.update(table, values, whereclause, null); public void insert(string table, ContentValues values) { mwritable.insert(table, null, values);
close()し 忘 れると エラーです 絶 対 に 閉 めましょう! public Database(Context context, String name, CursorFactory factory,int version) { super(context, name, factory, version); mwritable = getwritabledatabase(); mreadable = getreadabledatabase(); @Override public synchronized void close() { super.close(); mwritable.close(); mreadable.close();
Close()しないと ログでエラーが!
SQLiteの 再 構 成 は vacuum 定 期 的 にこれしないと deleteされたデータなんかが 残 って ファイルサイズが でかくなります public void vacuum() { mwritable.execsql("vacuum");
高 速 にデータを 取 り 出 して 加 工 して 挿 入! db.begintransaction(); try { SQLiteStatement stmt = db.compilestatement("insert into table values (?);"); for (String s : array) { stmt.bindstring(1, s); stmt.executeinsert(); //これを 呼 びださなければ ロールバックされる db.settransactionsuccessful(); finally { db.endtransaction();
ContentsProvider Cursorクラス
コンテンツプロバイダを 使 えば 1 行 で 簡 単 取 得! URIで データを 取 得 できます 別 アプリからでもOK! public class main extends Activity { @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); //SDカードの 曲 を 取 得 Cursor c = this.getcontentresolver().query( android.provider.mediastore.audio.media.external_content_uri, null, null, null, null);
マニュフェストファイルに URIを 書 きこむ! <provider android:authorities="jp.test.testdatabase" android:name=".dataprovider" /> ContentProviderを 継 承 して Query, insert, update などのメソッドを 書 くだけで 使 え ます! public class DataProvider extends ContentProvider { @Override public Cursor query(uri uri, String[] projection, String selection, String[] selectionargs, String sortorder) { @Override public Cursor query(uri uri, String[] projection, String selection, String[] selectionargs, String sortorder) {
Query, Insert, update, delete 以 外 にもなにかやりたければ URIにごりごり 追 加 して URI 解 析 してやります URIMATCHER = new UriMatcher(UriMatcher.NO_MATCH); URIMATCHER.addURI(AUTHORITY, "ほかの 処 理 1", 1); URIMATCHER.addURI(AUTHORITY, "ほかの 処 理 2", 2); int type = URIMATCHER.match(uri); switch ( type ) { Case 1: ほかの 処 理 1 break; Case 2: ほかの 処 理 2 break;
ありがとうございました!