愚鈍人プログラミングメモJavaAndroidSQLiteでデータベースSpinner(スピナー)-ドロップダウンリスト・ウィジェットAndroidコンテンツプロバイダプログラミングメモつれづれなるままに...個人的なメモSQLiteでデータベースアンドロイドでは、SQLiteというデータベースが、標準でサポートされています。SQLiteはWindow等の他のOSでも使う事ができ、JavaでもJDBCを使ってアクセスする事ができます。参照して、まず、SQLite単体での使い方に、慣れてみると良いと思います。SQLiteOpenHelperクラスとSQLiteDatabaseクラスアンドロイドでは、SQLiteDatabaseオブジェクトを使って、データベースを操作します。このクラスよりSQLiteDatabaseオブジェクトを取得します。以下に、その例を示します。リスト1(1)-ヘルパークラス(PersonOpenHelper.java)リスト1(2)-アクティビティクラス(SQLiteSample1.java)このプログラムを実行すると、以下のような画面がに表示されます。リスト1(1)で、ヘルパークラス「PersonOpenHelper.java」を定義しています。ヘルパークラスは、SQLiteOpenHelperクラスを継承しています。ヘルパークラスではコンストラクタで、スーパクラスSQLiteOpenHelperのコンストラクタを呼び出しています。第1引数は、データベースを所有するコンテキストオブジェクトを指定します。第2引数は、データベースファイルの名前です。この引数にnullを指定すると、データベースはメモリー上に作られます。どのようなものを指定するのかよくわかりません。無視して、常にnullを指定するという事で問題無いようです。第4引数は、データベースのバージョンを指定します。リスト1(1)では、データベースの最初のバージョンを示す1を指定しています。データベースのバージョンは、途中でデータベースの構成が変更になった等の場合に、これを管理するために使われます。SQLiteOpenHelperクラスはabstractクラスで、onCreateメソッドとonUpgradeメソッドを実装する必要があります。onCreateメソッドは、データベースが最初に作られる時に呼ばれます。リスト1(1)では、人を管理する「person_table」テーブルの作成と、3人分の初期データをテーブルに挿入しています。ここでSQL文を実行するために、execSQLメソッドを実行しています。execSQLメソッドについては、後述の「SQL文の実行-execSQLメソッド」を参照して下さい。onUpgradeメソッド(31行目)は、データベースが既に存在していて、そのデータベースのバージョンがコンストラクタで指定されたバージョンと異なる時に呼ばれるようです。ここでは、onUpgradeメソッドでは何も処理をしていません。後で、データベースの変更が生じた場合は、ここに処理を記述します。onUpgradeメソッドとデータベースのバージョンの管理の例については、後述の「データベースのバージョンアップのシナリオ」を参照して下さい。取得したデータの行数分だけTextViewにデータを表示しています。queryメソッドについては後述のSQLiteのCRUD(2)-データの検索とカーソルを参照して下さい。SQLiteDatabaseオブジェクトを取得するには、getWritableDatabaseメソッドもあります。getWritableDatabaseメソッドは読み書き用にデータベースをオープンすることです。closeメソッドを使ってデータベースをクローズする事を忘れないようにして下さい。(32行目)SQLiteのCRUD(1)-行の挿入・更新・削除SQLiteデータベースのCRUDを実行するには、いろいろなパターンがあります。SQL文の実行-execSQLメソッドSQLiteDatabaseオブジェクトよりSQL文を実行するには、引数にSQL文を示す文字列を指定して、execSQLメソッドを実行します。それ以外のいろいろなSQL文を実行できます。TABLE」を指定して、execSQLメソッドを実行しています。INTO」を指定して、execSQLメソッドを実行しています。(25,26,27行目)リスト1(1)のonCreateメソッド内のコードを、以下に再掲します。execSQLメソッドには、もう1つオーバオードされたメソッドが存在し、これを使うとSQL文に変数をバインドする事ができます。以下のコードは、このオーバオードされたメソッドを使ってリスト1(1)の25行目を書き換えた例です。次に示すように専用のメソッドも用意されています。行の挿入-insertメソッドテーブルの行にデータを挿入するには、insertメソッドが用意されています。insertメソッドを使うには、ContentValuesオブジェクトに挿入するデータをセットします。ContentValuesオブジェクトは、Hashmapのようなもので、列に対応するキーと値のペアを持ちます。以下に、リスト1(1)の25行目を、insertメソッドを使って書き換えた例を示します。insertメソッドの第1引数には、テーブル名を指定します。第2引数の意味は、理解できていませんが、とりあえずnullを指定しておけば良いようです。insertメソッドは、戻り値として行のIDを返します。SQLite入門が参考になると思います。行の更新-updateメソッド行を更新するには、updateというメソッドも用意されています。以下にupdateメソッドの例を示します。updateメソッドも、更新するデータをContentValuesオブジェクトにセットして使います。updateメソッドの第1引数には、insertメソッドと同様に、テーブル名を指定します。第2引数には、更新するデータをContentValuesオブジェクトで、指定します。第3引数には、更新するデータのwhere条件を指定します。圭佑」である行の年齢を、100才に更新します。この値をnullに指定すると、すべての行が更新対象になります。第4引数には、更新するデータのwhere条件を「?」を使ってパラメータで指定した場合の、パラメータ値をString配列で指定します。where条件にパラメータが無い場合は、上記の例のようにnullを指定します。以下に、where条件にパラメータを指定した例を示します。行の削除-deleteメソッド行を削除するには、deleteメソッドという、削除専用のメソッドも用意されています。以下に、deleteメソッドの例を示します。deleteメソッドの第1引数も、同様にテーブル名を指定します。第2引数には、削除する行のwhere条件を指定します。この値をnullに指定すると、すべての行が削除されます。第3引数には、更新するデータのwhere条件を「?」を使ってパラメータで指定した場合の、パラメータ値をString配列で指定します。where条件のパラメータが無い場合は、上記例のようにnullを指定します。以下に、where条件にパラメータを指定した例を示します。SQLiteのCRUD(2)-データの検索とカーソルexecSQLメソッドは値を返さないため、データベースのデータを取得する事はできません。代わりに、queryメソッドかrawQueryメソッドを使います。queryメソッドは、単純なSQLによるデータを取得には便利ですが、複雑なSQLをおこなうには、rawQueryメソッドを使った方が便利です。queryメソッドqueryメソッドには、幾つか、オーバロードされたメソッドが存在しますが、通常よく使われるのは、以下の引数のメソッドです。queryメソッドの第1引数には、テーブル名を指定します。第2引数には、取得するテーブルの列を、文字列配列で指定します。第3引数には、SQLのwhere条件を指定します。where条件には、パラメータ?を使う事ができ、パラメータ値を文字列配列で、第4引数で指定します。パラメータを使わない場合は、第4引数にはnullを指定します。BY」条件を指定します。以下に、オーバロードされたqueryメソッドの、構文を列挙します。メソッドの引数の変数名をみれば、SQL文と対比して、使い方はだいたい想像できると思います。limit)リスト1(2)の23、24行目に、queryメソッドのコードの例がありますが、これにwhere条件のパラメータを使って、25才以上のデータを取得する例を、以下に示します。SQL文にパラメータ?使われている場合は、パラメーター値を文字列配列で指定します(パラメータが使われていない場合はnull)。上記のqueryメソッドの例を、rawQueryメソッドを使って書き換えると、以下のようになります。SQLを使い慣れている方は、こちらの方が使いやすいでしょう。SQLiteQueryBuilderクラスSQLiteQueryBuilderクラスを使って、データの検索をおこなう事もできます。プロバイダ」を参照して下さい。カーソルqueryメソッドとrawQueryメソッドは、どちらもCursorオブジェクトを返します。カーソルは、Javaのイテレータのようなものと考えれば良いでしょう。カーソルを操作する事で、1行ずつデータを取得します。リスト1(2)の25行目~30行目のように、moveToFirstメソッドで最初の行に移動して、moveToNextメソッドで次の行に移動します。moveToFirstメソッドやmoveToNextメソッドなどの行移動メソッドは、戻り値として、移動する行が無い場合はfalseを返します。他にもgetStringメソッド等の列データ取得メソッド,getColumnNameメソッド等の列情報取得メソッドなどの、有益なメソッドがあります。Cursorクラスのリファレンスを参照して下さい。カーソルは、使い終わったらcloseメソッドを実行して、クローズするようにして下さい。リスト1(2)のように、whileループを使って行を走査する事もできますが、以下のようにgetCountメソッドで行数を取得して、forループを使う事もできます。プリコンパイルステートメントを使うと、処理スピードをアップさせる事ができます。以下に、リスト1(1)の25,26,27行目の3つの挿入処理を、プリコンパイルステートメントに置き換えた場合の例を示します。このメソッドを使うと、挿入された行のIDを取得する事ができます。以下に、その例を示します。おこなうには、以下のコ-ドのコメント部分(3行目)に、SQLの処理を記述します。endTransactionでトランザクションを終了します。処理はロールバックされコミットされません。CursorAdapterを使ってSQLiteの検索結果をListViewに表示する。ListViewに簡単に検索結果を表示する事ができます。以下に、その例を示します。リスト2-アクティビティクラス(SQLiteSample2.java)ここでは、ヘルパークラスとして、リスト1(1)のPersonOpenHelperクラスをそのまま利用します。このプログラムを実行すると、以下のようにCursorオブジェクトの各行がListViewに表示されます。CursorオブジェクトをAdapterクラスと組み合わせて使うには、Cursorオブジェクトに「_id」列を含んでいなければならないようです。この列を別名「_id」列として使っています。SQLite入門を参照して下さい。このような事をしなくても、すなおにテーブルに主キーとして「_id」列を定義して、検索結果列に出力させても良いです。データベースのバージョンアップのシナリオonUpgradeメソッドを使ったサンプルとして、あまり良い例ではありませんが、データベースをアップグレードするプログラムを作ってみました。onCreateメソッドとonUpgradeメソッドが、どのタイミングで呼ばれるのか確認する事ができます。データベースがファイルに保存されるようにする必要があります。DB_VERSIONが「1」の状態でプログラムを実行すると、最初の1回だけonCreateメソッドが呼ばれるのがわかります。次に、DB_VERSIONを「2」に変更すると、次の1回だけonUpgradeメソッドが実行されます。以下に、その時のログの出力を示します。テーブルの列にteam列を追加して、一般の人からスポーツ選手を管理するテーブルに変更をおこなっています。これにより、テーブル名もperson_tableからplayer_tableに変更しています。テーブルの移行時にエラーが発生した場合に、元に戻るようにトランザクション処理をおこなっています。ここでは新規にテーブルを作成して、前のテーブルのデータを1行づつコピーしています。後述する方法で、アンドロイドマシーン内部に作成したデーアベースファイルをWindowsにコピーして、データベースのテーブルの内容をDBViewerで確認してみました。DBViewerについては「eclipseのDBViewerプラグイン」を参照して下さい。意図どおりに、テーブルが変更されている事が確認できます。Windows・OSにコピーして、Windows上のツールを使って、データベースの内部を参照する事ができます。Windows・OS上でのSQLiteのツールについては、「JavaとSQLiteデータベース」を参照して下さい。ヘルパークラスによって作成されたデータベースファイルは、アンドロイドマシーン内の「/data/data/パッケージ名/databases」デレクトリに格納されています。「ファイル・エクスプローラー」タブを選択すると、アンドロイド内部のデレクトリを覗くことができます。「/data/data/gudon.sample.sqlite2/databases」デレクトリに「xxx.db」ファイルが格納されているはずです。Windows・OS上にファイルをコピーする事ができます。このデータベースファイルを、SQLiteのツールより指定すれば、データベースファイルの内容を確認できます。xxx.db内のデータを表示しているところです。アンドロイドのShellからSQLiteアンドロイドOSのshellから、SQLiteにアクセスする事もできます。アンドロイドOSのshellが起動します。このshellから「ls」等のLinuxコマンドが実行できます。日本語のデータを表示させようとすると、文字化けが発生してしまいます。このために、日本語のデータを表示させるには、ログの表示の時の「日本語のログ表示の文字化け」と同様、コマンドプロンプトの設定を変更する必要があります。コマンドプロンプトのフォント設定を、MSゴシックに変更します。(最初に1回だけ設定すれば良い。65001」にてコードページをutf-8に変更します。(コマンドプロンプトを起動するたびに毎回実行する必要があります。shell」と入力して、アンドロイドOSのshellを起動します。データベースファイル名」と入力してアンドロイドのSQLiteを起動します。これで、sqlite3のコマンドラインツールのコマンドが使えるようになります。終了する場合は、「.exit」コマンドでsqlite3のコマンドラインツールを終了させて、「exit」コマンドでアンドロイドのshellを終了させると、コマンドプロンプトに戻ります。アンドロイドOSのsqlite3のコマンドラインツールを起動して、person_tableの内容を表示した際の画面を以下に示します。日本語の表示の右端が表示されない事がありますが、コマンドプロンプトをスクロールさせると表示されます。