Help us understand the problem. What is going on with this article?

AndroidでSqliteデータベースを操作する - Kotlin編

最近は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に公開しています。

https://github.com/naosekig/KotlinSqliteSample

参考文献

android.database.sqlite | Android Developers
Android Sqliteプログラミング - Studio K's

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした