LoginSignup
20
15

More than 5 years have passed since last update.

KotlinでAndroidアプリのデータベースアクセスをしました。

Last updated at Posted at 2018-06-01

おはようございます。@naokiurです。

以前から興味があった、KotlinでAndroid開発を、
こっそりやっています。

よくある、 SQLiteOpenHelperを用いたデータベースアクセスを実装することができたので、
その内容を書き留めておきたいと思います。

環境

  • MacBook Pro (Retina 13-inch、Early 2015)
  • macOS High Sierra Capitan 10.13.2
  • Kotlin 1.2
  • Android Studio 3.1.2

目標

  • 画面に入力したタスク情報を、データベースに登録することができる。
    • よくあるタスク管理アプリ

実施したこと

  • 管理したいタスクの情報を決める
  • Contractクラスを作成する
  • Modelクラスを作成する
  • DatabaseHelperクラスを作成する
  • 画面に入力された情報を、DatabaseHelperクラスを用いて登録する、Activityクラスを作成する

管理したいタスクの情報を決める

シンプルに、1タスクは、以下のような情報を管理することとしました。

  • タスク名
  • ステータス
    • Doing(コード値: 0)
    • Done(コード値: 1)
  • 開始日
  • 終了日
  • 更新時刻

Contractクラスを作成する

データベーススキーマなどを定義する、Contractクラスを作成します。
今回は、1テーブル分なので効果は出ませんが、
データベース全体のテーブルの情報を、テーブル単位のインナークラスとして持っておくのが良い方法、
と書いてあるように見受けられました。(違ったらごめんなさい)

A good way to organize a contract class is to put definitions that are global to your whole database in the root level of the class.
Then create an inner class for each table. Each inner class enumerates the corresponding table's columns.

管理したいタスクの情報を元に、
以下のようなContractクラスを作成しました。

DBContract.kt
package jp.ne.naokiur.todomanagement.strage

import android.provider.BaseColumns

object DBContract {

    class TaskEntry : BaseColumns {
        companion object {
            const val TABLE_NAME = "tasks"
            const val TASK_NAME = "task_name"
            const val STATUS = "status"
            const val BEGIN_DATE = "begin_date"
            const val END_DATE = "end_date"
            const val UPDATE_TIME = "update_time"
        }
    }
}

Modelクラスを作成する

タスクデータを持ち運ぶためのModelクラスを作成します。
いわゆるDTOという理解をしています。

Contractクラスの定義を元に、
以下のようなModelクラスを作成しました。

TaskModel.kt
package jp.ne.naokiur.todomanagement.models

class TaskModel(val name: String, val status: String, val beginData: Long, val endDate: Long, val updateTime: Long)

DatabaseHelperクラスを作成する

データベースへアクセスするDatabaseHelperクラスを作成します。

ライブラリなどはあるのですが、今回はオーソドックスに、
SQLiteOpenHelperクラスを継承して作成します。

データベースの作成、およびINSERTができるように、
以下のようなDatabaseHelperクラスを作成しました。

TasksDatabaseHelper.kt
package jp.ne.naokiur.todomanagement.strage

import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteException
import android.database.sqlite.SQLiteOpenHelper
import jp.ne.naokiur.todomanagement.models.TaskModel

class TasksDatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
    @Throws(SQLiteException::class)
    fun insertTask(task: TaskModel): Boolean {
        val db = writableDatabase

        val values = ContentValues()
        values.put(DBContract.TaskEntry.TASK_NAME, task.name)
        values.put(DBContract.TaskEntry.STATUS, task.status)
        values.put(DBContract.TaskEntry.BEGIN_DATE, task.beginData)
        values.put(DBContract.TaskEntry.END_DATE, task.endDate)
        values.put(DBContract.TaskEntry.UPDATE_TIME, task.updateTime)

        val rowId = db.insert(DBContract.TaskEntry.TABLE_NAME, null, values)

        return true
    }

    override fun onCreate(db: SQLiteDatabase?) {
        db?.execSQL(SQL_CREATE_ENTRIES)
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        db?.execSQL(SQL_DELETE_ENTRIES)
        db?.execSQL(SQL_CREATE_ENTRIES)
    }

    override fun onDowngrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        onUpgrade(db, oldVersion, newVersion)
    }

    companion object {
        const val DATABASE_VERSION = 1
        const val DATABASE_NAME = "TASKS.db"

        private const val SQL_CREATE_ENTRIES =
                "CREATE TABLE " + DBContract.TaskEntry.TABLE_NAME + " (" +
                        DBContract.TaskEntry.TASK_NAME + " TEXT ," +
                        DBContract.TaskEntry.STATUS + " TEXT," +
                        DBContract.TaskEntry.BEGIN_DATE + " INTEGER," +
                        DBContract.TaskEntry.END_DATE + " INTEGER," +
                        DBContract.TaskEntry.UPDATE_TIME + " INTEGER)"

        private const val SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS " + DBContract.TaskEntry.TABLE_NAME
    }
} 

画面に入力された情報を、DatabaseHelperクラスを用いて登録する、Activityクラスを作成する

シンプルに、ボタンが押下された場合、
入力された値をデータベースに登録するActivityを作成します。

AddActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_main)
         val taskDatabaseHelper = TasksDatabaseHelper(this)
         val cal = Calendar.getInstance()
         val format = "yyyy/MM/dd"
         val dateFormat = SimpleDateFormat(format, Locale.JAPANESE)

         val beginDateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
            cal.set(Calendar.YEAR, year)
            cal.set(Calendar.MONTH, month)
            cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)

            begin_date!!.text = dateFormat.format(cal.time)
         }

         val limitDateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
            cal.set(Calendar.YEAR, year)
            cal.set(Calendar.MONTH, month)
            cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)

            limit_date!!.text = dateFormat.format(cal.time)
         }

         val beginDate = dateFormat.parse(begin_date.text.toString()).time
         val limitDate = dateFormat.parse(limit_date.text.toString()).time

         save_button.setOnClickListener { view ->
             val task = TaskModel(
                    task_name.text.toString(),
                     "0", // 初期値を `Doing`とする
                    beginDate,
                    limitDate,
                    Calendar.getInstance().timeInMillis
             )
             val result = taskDatabaseHelper.insertTask(task)

             if (result) {
                 Toast.makeText(this, "new Task Added!", LENGTH_LONG).show()
             }

         }

結果

画面に入力した値が、データベースに登録されていることを確認することができました。
(エミュレータ、DB Browser for SQliteで確認しました。)

スクリーンショット 2018-06-01 9.10.19.png

スクリーンショット 2018-06-01 9.10.59.png

今後

  • デザインががたがたなので調整する…
  • 画面上で現在のタスクを確認できるようにする
  • Doing/Doneはチェックボックスでやるつもりなので、Booleanに変換できるようにする

参考にさせていただきました。

20
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
15