So-net無料ブログ作成
検索選択

Androidアプリ開発 SQLiteデータベースを使用する SQLポケリ [Androidアプリ開発]



Androidには標準でSQLiteが搭載されている。SQLiteはリレーショナルデータベース。リレーショナルデータベースといえば、Oracle、DB2、SQL Serverなどが有名。SQLはリレーショナルデータベースを扱うときの命令群のこと。
SQLについての詳細は、手前味噌で恐縮ではあるが「SQLポケットリファレンス」を参照されたし。

[改訂第4版]SQLポケットリファレンス

[改訂第4版]SQLポケットリファレンス

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/02/18
  • メディア: 単行本(ソフトカバー)


Androidでは、大規模なデータを扱うことはない。せいぜい数メガがよいところであろう(動画はそれなりに大きいが、動画データはデータベースではない)。サーバ用のOracleやDB2ではなく、組み込み用に開発されたSQLiteで十分である。
SQLiteは小さいリレーショナルデータベースシステム。アプリに組み込まれることが前提のシステム。Oracleなどのようにサーバーとしてではなく、アプリに組み込んで使う。

Androidにサーバ的な用途は要求されないでしょう。

SQLite本家のURL
http://www.sqlite.org/

Oracleなどのサーバ形式のデータベースシステムでは、クライアントから接続して、SQLを投げ、その結果をレコードセット(カーソル)でもらい、結果を出力する、といったお決まりのパターンになる。
サーバに依存しないように、ある程度の抽象化がされている。依存する部分はプロバイダが吸収する。
サーバとの接続は、主にTCP/IPが使われる。

SQLiteの場合、アプリに組み込みが前提なので、TCP/IPによる通信は行われない。SQLiteのAPI関数を直接呼び出す感じで、SQL命令が投げられる。C言語によるSQLiteの基本的なAPI関数は以下の3つしかない。

sqlite *sqlite_open(const char *dbname, int mode, char **errmsg);

void sqlite_close(sqlite *db);

int sqlite_exec(
  sqlite *db,
  char *sql,
  int (*xCallback)(void*,int,char**,char**),
  void *pArg,
  char **errmsg
);


  sqlite_openでデータベースをオープンして
  sqlite_execでSQL命令を実行して
  sqlite_closeでデータベースをクローズ

JDBCを使ってSQLiteデータベースにアクセスすることも可能ではあるが、Androidの場合は、SQLiteDatabaseクラスを使ってアクセスを行う方が便利であろう。
SQLiteDatabaseクラスは、上記SQLiteのアクセス用APIをjavaのクラスでラップした感じになる。

では、具体的にはどうすればよいか説明していく。
まずは、データベースに接続を行う必要がある。SQLiteではデータベースはデータベースファイル毎に管理される。データベースファイルをオープンすることにより、そのデータベースに対して、SQL命令を投げることができるようになる。
データベースオープンは、SQLiteOpenHelperの派生クラスを作成し、そのヘルパークラスてオープンするのがAndroidでの作法となっている。
少々、まどろっこしいが、ヘルパークラスを作成することで、初回のアクセスでデータベースを作成されたときにテーブルを作ったり、バージョン管理ができるようになる。

ヘルパークラスの作成

では、SQLiteOpenHelperクラスの派生クラスを作成してみよう。

import android.database.sqlite.SQLiteOpenHelper;

public class MySQLiteOpenHelper extends SQLiteOpenHelper {
}


コンストラクタが必要と言われるので、作成する。

class MySQLiteOpenHelper extends SQLiteOpenHelper {
	static private String DB_NAME = "sample.db";
	static private int DB_VERSION = 1;
	public MySQLiteOpenHelper(Context context) {
		super(context, DB_NAME, null, DB_VERSION);
	}
}


クイックフィックスでコンストラクタを生成すると、データベースファイル名やらの引数が追加されてしまう。データベースファイル名、バージョンは、staticフィールドで指定したいので、引数からは削除。
スーパークラスのコンストラクタには、contextとデータベースファイル名、使用するCursorFactoryクラス、データベースのバージョンを与える必要がある。

コンストラクタは作成できたが、まだエラーになっているはず。
SQLiteOpenHelperクラスは、抽象クラスなので、実装すべきメソッドがいくつかある。

onCreate
onUpgrade

これらもクイックフィックスで作成してしまおう。
onCreateは、データベースファイルが作成された場合に呼び出されるもの。存在しないデータベースファイルにアクセスがあると自動的に作成される。作成された後で、onCreateが呼び出される。

onCreateでは、そのデータベースに必要なテーブルを作成するのに都合がよい。「テーブル」はデータベースの基本となるもので、CREATE TABLE命令で作成できる(SQLの詳細は、SQLポケットリファレンスをみてね)。

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL("CREATE TABLE IF NOT EXISTS sample(_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT)");
	}


sampleという名前のテーブルを作成した。列はふたつ_idとname。_idは自動インクリメントの列でプライマリキーとした。nameはTEXT型。SQLiteの場合、列の型は「指定しなくてもよい」。普通のデータベースは数値型、文字列型の区別があり、数値型の列に文字列データを突っ込むとエラーになったりするのだが、SQLiteでは変換は起こるが、エラーにはならない。なんと寛容なデータベースである。
列名は任意であるが、「_id」という名前にしてプライマリキーにしておくと「よいことがある」ので、Androidでテーブルを作成するときの定石となっている。

SQLiteのデータ型についても、SQLポケットリファレンス第4版を参照して欲しい。

サンプルでは、ひとつのテーブルしか作成していないが、データベースに複数のテーブルを作成することができる。ただし、同じ名前で作成することはできないので、複数作成する場合はテーブル名が重ならないようにする。

SQLiteには、ユーザの概念がない。接続したユーザによりスキーマが異なるということはない。名前空間はデータベースファイルでひとつになる。

onUpgradeはデータベースのバージョンが上がったときに呼び出される。アプリのバージョンアップでテーブルに列が追加になったりする。そうなった場合に、列を追加したり属性を変更したり、といったことができるようになっている。とりあえず、今回は実装しないので、スタブのままにしておく。

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
	}


これで、データベースオープンの準備はOK。完全なソースを載せておく。

package cx.fam.asai.TestSQLite;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class MySQLiteOpenHelper extends SQLiteOpenHelper {
	static private String DB_NAME = "sample.db";
	static private int DB_VERSION = 1;
	public MySQLiteOpenHelper(Context context) {
		super(context, DB_NAME, null, DB_VERSION);
	}
	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL("CREATE TABLE IF NOT EXISTS sample(_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT)");
	}
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
	}
}


データベースのオープン

実際にデータベースをオープンして、使ってみよう。
アクティビティからアクセスすることにする。onCreateでデータベースオープンをする。オープンにはMySQLiteOpenHelperを使う。

	MySQLiteOpenHelper helper = new MySQLiteOpenHelper(this);
	SQLiteDatabase db = helper.getReadableDatabase();


ヘルパーのインスタンスを作って、getReadableDatabase()を呼び出すとSQLiteDatabaseオブジェクトが戻ってくる。getReadableDatabaseなので、読み込み可能なデータベースが戻ってくる。SQLのSELECT命令だけを受け付ける。

	MySQLiteOpenHelper helper = new MySQLiteOpenHelper(this);
	SQLiteDatabase db = helper.getWritableDatabase();


書き込みを行うためには、getWritableDatabase()でデータベースオブジェクトを取得すればOK。読み込みに加えて、書き込みも行うことができるようになる。

SQL命令の実行

データベースをオープンできたので、SQL命令を発行してみよう。SQL命令は、SQLiteDatabase#execSQLを使うことで実行することができる。以下は、INSERT命令を実行する例。

	db.execSQL("INSERT INTO sample(name) VALUES('test')");


簡単ですな。
えっINSERT命令のsyntaxがわからない?!、では、SQLポケットリファ...

execSQLは値を戻さない。SELECT命令を実行する際は、SQLiteDatabase#rawQueryを使う。rawQueryはCursorオブジェクトを戻す。

	Cursor c = db.rawQuery("SELECT * FROM sample", null);
	boolean hasRecord = c.moveToFirst();
	while(hasRecord) {
    		android.util.Log.v("database sample", c.getInt(0) + "," + c.getString(1));
		hasRecord = c.moveToNext();
	}


moveToFirstで先頭のレコードに移動。カーソルが空であるとfalseが戻される。カーソルは、一度に1レコードしかアクセスできない。JDBCのレコードセットと同じ。次のレコードを参照するには、moveToNextを呼び出せばよい。最後まで行くとfalseが戻されるのでループを抜ける。

カーソルとデータベース接続は、使い終わったらcloseする。

	c.close();
	db.close();


アクティビティ側の全ソースも載せておく。

package cx.fam.asai.TestSQLite;

import android.app.Activity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;

public class TestSQLiteActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    	MySQLiteOpenHelper helper = new MySQLiteOpenHelper(this);
    	SQLiteDatabase db = helper.getWritableDatabase();
    	db.execSQL("INSERT INTO sample(name) VALUES('test')");
    	Cursor c = db.rawQuery("SELECT * FROM sample", null);
    	boolean hasRecord = c.moveToFirst();
    	while(hasRecord) {
    		android.util.Log.v("database sample", c.getInt(0) + "," + c.getString(1));
    		hasRecord = c.moveToNext();
    	}
    	c.close();
    	db.close();
    }
}


基本的には、こんなところを押さえておけばOKでしょう。後は、知っておくと便利なテクニックをいくつか紹介しておこうと思うのであるが、これは次回。

「改訂第4版SQLポケットリファレンス」は、SQLiteにも対応しています。


[改訂第4版]SQLポケットリファレンス

[改訂第4版]SQLポケットリファレンス

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/02/18
  • メディア: 単行本(ソフトカバー)



関連記事



かんたんAndroidアプリ作成入門 (プログラミングの教科書)

かんたんAndroidアプリ作成入門 (プログラミングの教科書)

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2013/04/16
  • メディア: 単行本(ソフトカバー)




サイト内を検索


タグ:Android SQL SQLite
nice!(1)  コメント(0) 
共通テーマ:携帯コンテンツ

nice! 1

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

Facebook コメント


AREarthroidPro ARで地球を表示するアプリ

Copyright Atsushi Asai Google+朝井淳
[改訂第4版]SQLポケットリファレンス

[改訂第4版]SQLポケットリファレンス

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/02/18
  • メディア: 単行本(ソフトカバー)

[データベースの気持ちがわかる]SQLはじめの一歩 (WEB+DB PRESS plus)

[データベースの気持ちがわかる]SQLはじめの一歩 (WEB+DB PRESS plus)

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2015/03/03
  • メディア: 単行本(ソフトカバー)
C言語 ポインタが理解できない理由 [改訂新版] (プログラミングの教科書)

C言語 ポインタが理解できない理由 [改訂新版] (プログラミングの教科書)

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2011/04/08
  • メディア: 単行本(ソフトカバー)

かんたんAndroidアプリ作成入門 (プログラミングの教科書)

かんたんAndroidアプリ作成入門 (プログラミングの教科書)

  • 作者: 朝井 淳
  • 出版社/メーカー: 技術評論社
  • 発売日: 2013/04/16
  • メディア: 単行本(ソフトカバー)