Kotlinで画像をデータベースに保存したい

#目的
Kotlinでデータベース接続をし、画像の追加、削除までを実装する。

#環境
Android Studio 3.5.2
Build #AI-191.8026.42.35.5977832, built on October 31, 2019
JRE: 1.8.0_202-release-1483-b03 amd64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Windows 10 10.0

##KotlinでのDB接続の手順
適当なクラス名でKotlinファイルを作成します。
###まずは定義を記述

```kotlin:DbHelper.kt
//テーブル定義
object PhotoTable : BaseColumns {
    const val TABLE_NAME = "photo"
    const val COLUMN_NAME_BITMAP = "bitmap"
}

//テーブル作成のSQL
private const val SQL_CREATE_PHOTO = "CREATE TABLE ${PhotoTable.TABLE_NAME}" +
        " (${BaseColumns._ID} INTEGER PRIMARY KEY," +
        " ${PhotoTable.COLUMN_NAME_BITMAP} BLOB NOT NULL)"
//テーブル削除のSQL
private const val SQL_DELETE_PHOTO = "DROP TABLE IF EXISTS ${PhotoTable.TABLE_NAME}"

private const val DATABASE_VERSION = 1
private const val DATABASE_NAME = "Practice.db"
```
画像は**バイナリーデータとして保存**するので型は**BLOB**になります。
###SQLiteOpenHelperクラスを継承
```kotlin:DbHelper.kt
class DbHelper(context: Context): SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
    override fun onCreate(db: SQLiteDatabase) {
        db.execSQL(SQL_CREATE_PHOTO)
    }
    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        db.execSQL(SQL_DELETE_PHOTO)
        onCreate(db)
    }
}
```
今回は最低限オーバーライドする必要があるCreateとUpgradeのみです。
##UI
![viewを配置.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590405/35597c76-69ca-d140-1126-7533a2f8e656.png)
1. 画像表示用ImageView(id:imageView)
2. 画像追加ボタン(id:addPhotoButton)
3. 画像削除ボタン(id:deletePhotoButton)

##レコ―ドの追加
###画像追加ボタンのクリック処理
```kotlin:MainActivity.kt
addPhotoButton.setOnClickListener{
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) 
    intent.addCategory(Intent.CATEGORY_OPENABLE)
    intent.type = "image/*"

    startActivityForResult(Intent.createChooser(intent,"写真を選択"),CHOOSE_PHOTO)
}
```
画像を選択するActivityを起動します。
###画像選択後の処理
```kotlin:MainActivity.kt
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)

    if(requestCode == CHOOSE_PHOTO
        && resultCode == Activity.RESULT_OK
        && data != null){

        //選択した画像のUriからBitmapを取得
        val bitmap = getBitmapFromUri(data.data)
        bitmap?:return

        //画像表示用のImageViewに表示させときます
        imageView.setImageBitmap(bitmap)

        //Bitmapをバイナリーに変換してDBに登録します
        val values = getContentValues(getBinaryFromBitmap(bitmap))
        val db = dbHelper.writableDatabase
        photoId = db.insert(PhotoTable.TABLE_NAME, null, values) //レコード追加
        db.close()

        Toast.makeText(this,"登録しました",Toast.LENGTH_LONG).show()
    }
}

//Bitmapを取得
//@param 画像Uri
//@return Bitmap
private fun getBitmapFromUri(uri: Uri?): Bitmap? {
    uri?:return null

    val parcelFileDescriptor: ParcelFileDescriptor? =
        this.contentResolver.openFileDescriptor(uri, "r")
    parcelFileDescriptor?:return null

    val fileDescriptor: FileDescriptor = parcelFileDescriptor.fileDescriptor
    val image: Bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor)
    parcelFileDescriptor.close()
    return image
}

//Binaryを取得
//@param Bitmap
//@return Binary
private fun getBinaryFromBitmap(bitmap:Bitmap):ByteArray{
    val byteArrayOutputStream = ByteArrayOutputStream()
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)
    return byteArrayOutputStream.toByteArray()
}

//値セットを取得
//@param URI
//@return 値セット
private fun getContentValues(binary:ByteArray): ContentValues {
    return ContentValues().apply {
        put("${PhotoTable.COLUMN_NAME_BITMAP}",binary)
    }
}
```
レコードの追加は以上です。

##レコードの削除
###画像削除ボタンのクリック処理
```kotlin:MainActivity.kt
deletePhotoButton.setOnClickListener{
    val db = dbHelper.writableDatabase
    db.delete(PhotoTable.TABLE_NAME,"_ID = $photoId",null) //レコード削除
    db.close()

    //画像表示用ImageViewを元のに戻してます
    imageView.setImageResource(R.drawable.art)

    Toast.makeText(this,"削除しました",Toast.LENGTH_LONG).show()
}
```
レコードの削除は以上です。

#まとめ
1. SQLiteOpenHelperを理解する  
https://developer.android.com/reference/kotlin/android/database/sqlite/SQLiteOpenHelper
2. 画像をバイナリーに変換する
　ちなみに、バイナリーをBitmapに変換する際は

```kotlin
val binary = //DBから取得したBinary
val bitmap = BitmapFactory.decodeByteArray(binary,0,binary.size)
```
で、取得できます。
##参考にしたサイトとソースコード
参考サイト
https://developer.android.com/training/data-storage/sqlite?hl=ja

ソースコード
https://github.com/date62noka3/database-kotlin

#最後に
補足という形で新たに記事を投稿しました。
合わせてお読みください。
https://qiita.com/date62noka3/items/573dbf84b41013ed9812