SQLiteデータベース

データベースの保存先

パッケージ名がcom.example.myapp、データベース名がexample.dbだった場合、

/data/data/com.example.myapp/databases/example.db に保存されます。

DatabaseHelper.kt

class DatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION){

    // クラス全体で共有する値を定義 
    companion object {
        private const val DATABASE_NAME = "example.db"
        private const val DATABASE_VERSION = 1
        const val TABLE_NAME = "data_table"
    }

    // onCreateメソッドは初期状態(データベースが作成されていなければ)に1回だけ実行されます
    override fun onCreate(db: SQLiteDatabase?) {
        val sql = """
            CREATE TABLE $TABLE_NAME (
                _id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL,
                age INTEGER NOT NULL
            )
        """.trimIndent()
        db?.execSQL(sql)
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldversion: Int, newVersion: Int) {
        db?.execSQL("DROP TABLE IF EXISTS $TABLE_NAME")
        onCreate(db)
    }

    // データの挿入
    fun insertData(name: String, age: Int): Boolean {
        val db = this.writableDatabase
        val values = ContentValues().apply {
            put("name", name)
            put("age", age)
        }
        val result = db.insert(TABLE_NAME, null, values)
        db.close()
        return true
    }

    // データの取得
    fun getAllData(): List<Map<String, Any>> {
        val db = this.readableDatabase
        val dataList = mutableListOf<Map<String, Any>>()
        val cursor = db.query(
            TABLE_NAME,
            null, // すべての列を取得
            null, // WHERE句なし
            null, // WHERE句に渡す引数なし
            null, // GROUP BY句なし
            null, // HAVING句なし
            null, // 並び替えなし
        )

        if (cursor.moveToFirst()) {
            do {
                val id = cursor.getInt(cursor.getColumnIndexOrThrow("_id"))
                val name = cursor.getString(cursor.getColumnIndexOrThrow("name"))
                val age = cursor.getInt(cursor.getColumnIndexOrThrow("age"))
                val data = mapOf(
                    "_id" to id,
                    "name" to name,
                    "age" to age
                )
                dataList.add(data)
            } while (cursor.moveToNext())
        }

        // オブジェクトの解放
        cursor.close()
        db.close()
        return dataList
    }
}

cursorはマス目状になっており、cursor.moveToFirst()で最初の0行目を表示します。

cursor.moveToNext()で一行進みます。進めない場合はFalseを返します。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:id="@+id/etName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Name" />

    <EditText
        android:id="@+id/etAge"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Age"
        android:inputType="number" />

    <Button
        android:id="@+id/btnSave"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Save" />
</LinearLayout>

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private lateinit var databaseHelper: DatabaseHelper

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_main)

        // DatabaseHelper.ktのDatabaseHelperクラスのインスタンスを生成する
        databaseHelper = DatabaseHelper(this)

       
        val btnSave = findViewById<Button>(R.id.btnSave)
        val btnSaveListener = BtnSaveListener()
        btnSave.setOnClickListener(btnSaveListener)

        val btnDisplay = findViewById<Button>(R.id.btnDisplay)
        val btnDisplayListener = BtnDisplayListener()
        btnDisplay.setOnClickListener(btnDisplayListener)

    }


    private inner class BtnSaveListener: View.OnClickListener {
        override fun onClick(view: View) {
            val etName = findViewById<EditText>(R.id.etName)
            val etAge = findViewById<EditText>(R.id.etAge)
            val name = etName.text.toString()
            val age = etAge.text.toString().toIntOrNull()  <--- 数字でなければNULLを返す
         
            if (name.isNotEmpty() && age.isNotEmpty() ) {
                val inserted = databaseHelper.insertData(name, age)
                if (inserted) {
                    Toast.makeText(this@MainActivity, "DATA SAVED!", Toast.LENGTH_LONG).show()
                } else {
                    Toast.makeText(this@MainActivity, "FAILED TO SAVE DATA", Toast.LENGTH_LONG).show()
                }
            }
        }    
    }


    private inner class BtnDisplayListener: View.OnClickListener {
        override fun onClick(view: View) {
            val tvMemo = findViewById<TextView>(R.id.tvMemo)
            val dataList = databaseHelper.getAllData()

            if (dataList.isNotEmpty()) {
                val displayText = dataList.joinToString(separator = "\n") { data ->
                    val id =data["_id"]
                    val name = data["name"]
                    val age = data["age"]
                    "ID: $id | NAME: $name | AGE: $age"
                }
                tvMemo.text = displayText
            } else {
                tvMemo.text = "NO DATA FOUND"
            }
        }
    }
}

※1 … アンダースコア( _ )はその変数がprivate変数であることを「開発者がわかりやすくするための命名ルール(慣習)」であり、特に意味はありません。

また、privateをつけることでその変数はclass外で呼び出せなくなります。