最近はAndroidアプリをKotlinで作成する機会が増えました。
そこで以前Javaで記載したSqliteデータベースの操作方法の記事をKotlinで書き直してみました。
環境:API 29、Android Studio 3.5
#データベース定義とテーブル作成
まずSQLiteOpenHelperを継承したクラスを作成しデータベースを定義します。
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
---------- (中略) ----------
private class SampleDBHelper(context: Context, databaseName:String, factory: SQLiteDatabase.CursorFactory?, version: Int) : SQLiteOpenHelper(context, databaseName, factory, version) {
override fun onCreate(database: SQLiteDatabase?) {
database?.execSQL("create table if not exists SampleTable (id text primary key, name text, type integer, image BLOB)");
}
override fun onUpgrade(database: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
if (oldVersion < newVersion) {
database?.execSQL("alter table SampleTable add column deleteFlag integer default 0")
}
}
}
SQLiteOpenHelperは引数にContext、データベース名、SQLiteDatabase.CursorFactory、バージョン番号を持ちます。
そして以下の2つのイベントをoverrideする必要があります。
・onCreate
データベースが初期作成された時に発生するイベントです。
このサンプルでは以下のフィールドを持つSampleTableというテーブルを作成するCREATE TABLE文を実行しています。
フィールド名 | データ型 | 補足 |
---|---|---|
id | 文字列型 | 主キー |
name | 文字列型 | |
type | 数値型 | |
image | BLOB型 | |
最後のBLOB型はImageViewに表示しているBitmapをバイト配列にしてSqliteのテーブルに保存する為のデータ型です。 |
・onUpgrade
SQLiteOpenHelperに渡されるバージョン番号が変わった時に発生するイベントです。
このサンプルではSampleTableに以下のフィールドを追加するALTER TABLE文を実行しています。
フィールド名 | データ型 | 補足 |
---|---|---|
deleteFlag | 数値型 | 初期値:0 |
#データベースへのアクセス
続いてデータベースへのアクセス方法をご紹介します。
まず最初に作成したSQLLiteOpenHelperを継承したクラスを呼び出します。
val dbHelper = SampleDBHelper(applicationContext, "SampleDB", null, 1);
そしてSQLLiteOpenHelperからデータベースを操作する為のSQLiteDatabaseを取得します。
この時、SELECTのみを行いたい場合はreadableDatabaseメソッドを実行し、読み取り専用のSQLiteDatabaseを取得します。
val database = dbHelper.readableDatabase
INSERT、UPDATE、DELETEを行いたい場合はwritableDatabaseメソッドを実行し、書き込み可能なSQLiteDatabaseを取得します。
val database = dbHelper.writableDatabase
では実際にSampleTableに対してINSERT、UPDATE、DELETE、SELECTを実行してみましょう。
#INSERT
import android.app.Activity
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import java.io.ByteArrayOutputStream
class MainActivity : AppCompatActivity() {
private val dbName: String = "SampleDB"
private val tableName: String = "SampleTable"
private val dbVersion: Int = 1
---------- (中略) ----------
private fun insertData(id: String, name: String, type: Int, bitmap: Bitmap) {
try {
val dbHelper = SampleDBHelper(applicationContext, dbName, null, dbVersion);
val database = dbHelper.writableDatabase
val values = ContentValues()
values.put("id", id)
values.put("name", name)
values.put("type", type)
val byteArrayOutputStream = ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)
val bytes = byteArrayOutputStream.toByteArray()
values.put("image", bytes)
database.insertOrThrow(tableName, null, values)
}catch(exception: Exception) {
Log.e("insertData", exception.toString())
}
}
}
このサンプルではSampleTableに対してINSERTを実行しています。
INSERTをする際にはSQLiteDatabaseのinsertOrThrowメソッドを実行します。SQLiteDatabaseにはinsertメソッドもあるのですが、insertメソッドはINSERTに失敗した時にエラーハンドリングができない為、使用しない方がいいでしょう。
INSERTする値はContentValuesにセットしてinsertOrThrowメソッドに渡します。
#UPDATE
import android.app.Activity
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import java.io.ByteArrayOutputStream
class MainActivity : AppCompatActivity() {
private val dbName: String = "SampleDB"
private val tableName: String = "SampleTable"
private val dbVersion: Int = 1
---------- (中略) ----------
private fun updateData(whereId: String, newName: String, newType: Int, newBitmap: Bitmap) {
try {
val dbHelper = SampleDBHelper(applicationContext, dbName, null, dbVersion);
val database = dbHelper.writableDatabase
val values = ContentValues()
values.put("name", newName)
values.put("type", newType)
val byteArrayOutputStream = ByteArrayOutputStream();
newBitmap?.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)
val bytes = byteArrayOutputStream.toByteArray()
values.put("image", bytes)
val whereClauses = "id = ?"
val whereArgs = arrayOf(whereId)
database.update(tableName, values, whereClauses, whereArgs)
}catch(exception: Exception) {
Log.e("updateData", exception.toString())
}
}
}
このサンプルではidをWhere句に指定して、該当idのname、type、imageの値を更新しています。
UPDATEを行う際にはSQLiteDatabaseのupdateメソッドを使用します。
まずUPDATEする値はINSERTの時と同様にContentValuesに設定します。
次にWHERE句を以下の様に指定します。
・WHERE句の構文をString型で設定
val whereClauses = "id = ?"
WHERE句の条件が複数ある場合は"and"もしくは"or"でつなげることができます。
・WHERE句の値をString[]型で設定
val whereArgs = arrayOf(whereId)
上記のWhereClausesで指定した順にString配列に値を設定します。
#DELETE
import android.app.Activity
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.graphics.drawable.BitmapDrawable
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
class MainActivity : AppCompatActivity() {
private val dbName: String = "SampleDB"
private val tableName: String = "SampleTable"
private val dbVersion: Int = 1
---------- (中略) ----------
private fun deleteData(whereId: String) {
try {
val dbHelper = SampleDBHelper(applicationContext, dbName, null, dbVersion);
val database = dbHelper.writableDatabase
val whereClauses = "id = ?"
val whereArgs = arrayOf(whereId)
database.delete(tableName, whereClauses, whereArgs)
}catch(exception: Exception) {
Log.e("deleteData", exception.toString())
}
}
}
このサンプルではidをWhere句に指定して、該当idのレコードを削除しています。
DELETEを行う際にはSQLiteDatabaseのdeleteメソッドを使用します。
UPDATEと同様にWHERE句の値を指定して実行します。
#SELECT
import android.app.Activity
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import java.io.ByteArrayOutputStream
class MainActivity : AppCompatActivity() {
private val dbName: String = "SampleDB"
private val tableName: String = "SampleTable"
private val dbVersion: Int = 1
private var arrayListId: ArrayList<String> = arrayListOf()
private var arrayListName: ArrayList<String> = arrayListOf()
private var arrayListType: ArrayList<Int> = arrayListOf()
private var arrayListBitmap: ArrayList<Bitmap> = arrayListOf()
---------- (中略) ----------
private fun selectData() {
try {
arrayListId.clear();arrayListName.clear();arrayListType.clear();arrayListBitmap.clear()
val dbHelper = SampleDBHelper(applicationContext, dbName, null, dbVersion)
val database = dbHelper.readableDatabase
val sql = "select id, name, type, image from " + tableName + " where type in (1, 2) order by id"
val cursor = database.rawQuery(sql, null)
if (cursor.count > 0) {
cursor.moveToFirst()
while (!cursor.isAfterLast) {
arrayListId.add(cursor.getString(0))
arrayListName.add(cursor.getString(1))
arrayListType.add(cursor.getInt(2))
val blob: ByteArray = cursor.getBlob(3)
val bitmap = BitmapFactory.decodeByteArray(blob, 0, blob.size)
arrayListBitmap.add(bitmap)
cursor.moveToNext()
}
}
}catch(exception: Exception) {
Log.e("selectData", exception.toString());
}
}
}
SELECTを行う際にはSQLiteDatabaseのrawQueryメソッドを使用し、その引数にSELECTを行うSQL文を設定します。
rawQueryメソッド自体はその名の通り生のSQL文を実行するメソッドなので、SELECT文以外でも使えます。
SQLの実行結果はCursorクラスで受け取ることができますので、moveToFirstメソッドで最初のレコードに移動し、最後のレコードに到達するまでmoveToNextメソッドを繰り返して全レコードの値を取得します。
#サンプルプログラム
上記のコードを使用したサンプルプログラムをGitHubに公開しています。
#参考文献
android.database.sqlite | Android Developers
Android Sqliteプログラミング - Studio K's