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外で呼び出せなくなります。