KotlinでAndroidアプリにSQLiteデータベースとRecyclerViewを連携させる方法を解説
この記事では、Kotlinを使ってAndroidアプリ内のデータベース(SQLite)とRecyclerViewを連携させる方法を、連絡先管理アプリを例に段階的に解説します。データベースへの追加・編集・削除といった基本操作を含む実装例なので、CRUD処理の学習にも最適です。
ステップ1:新規プロジェクトを作成する
Android Studioを起動し、「File」→「New Project」を選択して、必要な情報を入力しながら新しいプロジェクトを作成します。
ステップ2:activity_main.xml にコードを追加する
まず、メイン画面となるレイアウトファイル「res/layout/activity_main.xml」に以下のコードを記述します。連絡先一覧を表示するRecyclerViewと、新規追加用のボタンを配置しています。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="4dp"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/myContactList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="50dp"
android:paddingBottom="8dp" />
<Button
android:id="@+id/btnAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="16dp"
android:layout_marginBottom="4dp"
android:padding="2dp"
android:text="ADD" />
</FrameLayout>
ステップ3:MainActivity.kt を実装する
次に「src/MainActivity.kt」に以下のコードを追加します。このクラスでは、データベースから連絡先リストを取得してRecyclerViewに表示し、ボタン押下時に新規登録用ダイアログを表示する処理を行っています。
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
class MainActivity : AppCompatActivity() {
private lateinit var dataBase: SqliteDatabase
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
title = "KotlinApp"
val contactView: RecyclerView = findViewById(R.id.myContactList)
val linearLayoutManager = LinearLayoutManager(this)
contactView.layoutManager = linearLayoutManager
contactView.setHasFixedSize(true)
dataBase = SqliteDatabase(this)
val allContacts = dataBase.listContacts()
if (allContacts.size > 0) {
contactView.visibility = View.VISIBLE
val mAdapter = ContactAdapter(this, allContacts)
contactView.adapter = mAdapter
}
else {
contactView.visibility = View.GONE
Toast.makeText(
this,
"There is no contact in the database. Start adding now",
Toast.LENGTH_LONG
).show()
}
val btnAdd: Button = findViewById(R.id.btnAdd)
btnAdd.setOnClickListener { addTaskDialog() }
}
private fun addTaskDialog() {
val inflater = LayoutInflater.from(this)
val subView = inflater.inflate(R.layout.add_contacts, null)
val nameField: EditText = subView.findViewById(R.id.enterName)
val noField: EditText = subView.findViewById(R.id.enterPhoneNum)
val builder = AlertDialog.Builder(this)
builder.setTitle("Add new CONTACT")
builder.setView(subView)
builder.create()
builder.setPositiveButton("ADD CONTACT") { _, _ ->
val name = nameField.text.toString()
val phoneNum = noField.text.toString()
if (TextUtils.isEmpty(name)) {
Toast.makeText(
this@MainActivity,
"Something went wrong. Check your input values",
Toast.LENGTH_LONG
).show()
}
else {
val newContact = Contacts(name, phoneNum)
dataBase.addContacts(newContact)
finish()
startActivity(intent)
}
}
builder.setNegativeButton("CANCEL") { _, _ -> Toast.makeText(this@MainActivity, "Task cancelled",
Toast.LENGTH_LONG).show()}
builder.show()
}
override fun onDestroy() {
super.onDestroy()
dataBase.close()
}
}
ステップ4:Kotlinクラスファイルを作成する
続いて、以下の4つのKotlinクラスファイルを作成し、それぞれ対応するコードを記述していきます。
Contacts.kt
連絡先データ(ID・名前・電話番号)を保持するモデルクラスです。
class Contacts {
var id = 0
var name: String
var phno: String
internal constructor(name: String, phno: String) {
this.name = name
this.phno = phno
}
internal constructor(id: Int, name: String, phno: String) {
this.id = id
this.name = name
this.phno = phno
}
}
ContactViewHolder.kt
RecyclerViewの各行ビューへの参照を保持するViewHolderクラスです。
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class ContactViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var tvName: TextView = itemView.findViewById(R.id.contactName)
var tvPhoneNum: TextView = itemView.findViewById(R.id.phoneNum)
var deleteContact: ImageView = itemView.findViewById(R.id.deleteContact)
var editContact: ImageView = itemView.findViewById(R.id.editContact)
}
ContactAdapter.kt
RecyclerViewにデータを供給するアダプタークラスです。検索機能(Filterable)や、行ごとの編集・削除処理もここに実装されています。
import android.app.Activity
import android.content.Context
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.EditText
import android.widget.Filter
import android.widget.Filterable
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.RecyclerView
import java.util.*
internal class ContactAdapter(private val context: Context, listContacts: ArrayList<Contacts>) :
RecyclerView.Adapter<ContactViewHolder>(), Filterable {
private var listContacts: ArrayList<Contacts>
private val mArrayList: ArrayList<Contacts>
private val mDatabase: SqliteDatabase
init {
this.listContacts = listContacts
this.mArrayList = listContacts
mDatabase = SqliteDatabase(context)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ContactViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.contact_list_layout, parent, false)
return ContactViewHolder(view)
}
override fun onBindViewHolder(holder: ContactViewHolder, position: Int) {
val contacts = listContacts[position]
holder.tvName.text = contacts.name
holder.tvPhoneNum.text = contacts.phno
holder.editContact.setOnClickListener { editTaskDialog(contacts) }
holder.deleteContact.setOnClickListener {
mDatabase.deleteContact(contacts.id)
(context as Activity).finish()
context.startActivity(context.intent)
}
}
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(charSequence: CharSequence): FilterResults {
val charString = charSequence.toString()
listContacts = if (charString.isEmpty()) {
mArrayList
}
else {
val filteredList = ArrayList<Contacts>()
for (contacts in mArrayList) {
if (contacts.name.toLowerCase().contains(charString)) {
filteredList.add(contacts)
}
}
filteredList
}
val filterResults = FilterResults()
filterResults.values = listContacts
return filterResults
}
override fun publishResults(
charSequence: CharSequence,
filterResults: FilterResults
)
{
listContacts =
filterResults.values as ArrayList<Contacts>
notifyDataSetChanged()
}
}
}
override fun getItemCount(): Int {
return listContacts.size
}
private fun editTaskDialog(contacts: Contacts) {
val inflater = LayoutInflater.from(context)
val subView = inflater.inflate(R.layout.add_contacts, null)
val nameField: EditText = subView.findViewById(R.id.enterName)
val contactField: EditText = subView.findViewById(R.id.enterPhoneNum)
nameField.setText(contacts.name)
contactField.setText(contacts.phno)
val builder = AlertDialog.Builder(context)
builder.setTitle("Edit contact")
builder.setView(subView)
builder.create()
builder.setPositiveButton(
"EDIT CONTACT"
) { _, _ ->
val name = nameField.text.toString()
val phNo = contactField.text.toString()
if (TextUtils.isEmpty(name)) {
Toast.makeText(
context,
"Something went wrong. Check your input values",
Toast.LENGTH_LONG
).show()
}
else {
mDatabase.updateContacts(
Contacts(
Objects.requireNonNull<Any>(contacts.id) as Int,
name,
phNo
)
)
(context as Activity).finish()
context.startActivity(context.intent)
}
}
builder.setNegativeButton(
"CANCEL"
) { _, _ -> Toast.makeText(context, "Task cancelled", Toast.LENGTH_LONG).show() }
builder.show()
}
}
SqliteDatabase.kt
SQLiteOpenHelperを継承したデータベース操作クラスです。テーブル作成、および連絡先の一覧取得・追加・更新・削除の各メソッドを実装しています。
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import java.util.*
class SqliteDatabase internal constructor(context: Context?) :
SQLiteOpenHelper(
context,
DATABASE_NAME,
null,
DATABASE_VERSION
) {
override fun onCreate(db: SQLiteDatabase) {
val createContactTable = ("CREATE TABLE "
+ TABLE_CONTACTS + "(" + COLUMN_ID
+ " INTEGER PRIMARY KEY,"
+ COLUMN_NAME + " TEXT,"
+ COLUMN_NO + " INTEGER" + ")")
db.execSQL(createContactTable)
}
override fun onUpgrade(
db: SQLiteDatabase,
oldVersion: Int,
newVersion: Int
) {
db.execSQL("DROP TABLE IF EXISTS $TABLE_CONTACTS")
onCreate(db)
}
fun listContacts(): ArrayList<Contacts> {
val sql = "select * from $TABLE_CONTACTS"
val db = this.readableDatabase
val storeContacts =
ArrayList<Contacts>()
val cursor = db.rawQuery(sql, null)
if (cursor.moveToFirst()) {
do {
val id = cursor.getString(0).toInt()
val name = cursor.getString(1)
val phno = cursor.getString(2)
storeContacts.add(Contacts(id, name, phno))
}
while (cursor.moveToNext())
}
cursor.close()
return storeContacts
}
fun addContacts(contacts: Contacts) {
val values = ContentValues()
values.put(COLUMN_NAME, contacts.name)
values.put(COLUMN_NO, contacts.phno)
val db = this.writableDatabase
db.insert(TABLE_CONTACTS, null, values)
}
fun updateContacts(contacts: Contacts) {
val values = ContentValues()
values.put(COLUMN_NAME, contacts.name)
values.put(COLUMN_NO, contacts.phno)
val db = this.writableDatabase
db.update(
TABLE_CONTACTS,
values,
"$COLUMN_ID = ?",
arrayOf(contacts.id.toString())
)
}
fun deleteContact(id: Int) {
val db = this.writableDatabase
db.delete(
TABLE_CONTACTS,
"$COLUMN_ID = ?",
arrayOf(id.toString())
)
}
companion object {
private const val DATABASE_VERSION = 5
private const val DATABASE_NAME = "Contacts"
private const val TABLE_CONTACTS = "Contacts"
private const val COLUMN_ID = "_id"
private const val COLUMN_NAME = "contactName"
private const val COLUMN_NO = "phoneNumber"
}
}
ステップ5:レイアウトリソースファイルを作成する
入力ダイアログ用とリスト行表示用の2つのレイアウトファイル(add_contacts.xml と contact_list_layout.xml)を作成し、以下のコードを追加します。
add_contacts.xml
名前と電話番号を入力するためのEditTextを縦に並べたシンプルなレイアウトです。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/enterName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:hint="Enter Name"
android:inputType="text"
android:maxLines="1"
android:padding="12dp"
android:textSize="12sp" />
<EditText
android:id="@+id/enterPhoneNum"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginEnd="8dp"
android:hint="Enter Number"
android:inputType="phone"
android:maxLines="1"
android:padding="12dp"
android:textSize="12sp" />
</LinearLayout>
contact_list_layout.xml
CardViewを使って、連絡先の名前・電話番号に加え、編集・削除アイコンを横並びで表示する行レイアウトです。
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="1dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="12dp">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/contactName"
android:layout_width="220dp"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="@+id/phoneNum"
android:layout_width="220dp"
android:layout_height="wrap_content"
android:layout_below="@+id/contactName"
android:textSize="12sp"
android:textStyle="bold" />
</RelativeLayout>
<ImageView
android:id="@+id/editContact"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:contentDescription="TODO"
android:src="@drawable/ic_baseline_edit_24" />
<ImageView
android:id="@+id/deleteContact"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:contentDescription="TODO"
android:src="@drawable/ic_baseline_remove_24" />
</LinearLayout>
</androidx.cardview.widget.CardView>
ステップ6:AndroidManifest.xml にコードを追加する
最後に、マニフェストファイル「androidManifest.xml」に以下のコードを記述します。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.q11">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
アプリを実行してみよう
それでは、実際にアプリケーションを起動してみましょう。ここでは、実機のAndroidスマートフォンがパソコンに接続されているものとして説明を進めます。Android Studioからプロジェクト内のアクティビティファイルを開き、ツールバーにあるRunアイコンをクリックしてください。表示された候補から自分のモバイルデバイスを選択すると、端末上にアプリの初期画面が表示されます。
アプリを起動すると、まず空の状態でトーストメッセージが表示されます。「ADD」ボタンをタップして連絡先を追加すると、RecyclerViewにカード形式のリストが表示され、各行の編集アイコン・削除アイコンからデータベースの内容を更新できることが確認できます。
-
【Android】データベースとRecyclerViewを連携させる方法を実装例つきで解説
この記事では、AndroidアプリでRecyclerViewとデータベース(SQLite)を連携させて使用する方法を、実際のサンプルコードとともに解説します。連絡先の登録・表示・編集・削除ができるシンプルなアプリを題材に、実装手順をステップごとに見ていきましょう。ステップ1:プロジェクトの作成と依存関係の追加まず、Android Studioで新しいプロジェクトを作成します。メニューから「File → New Project」を選択し、必要事項を入力してプロジェクトを作成してください。続いて、build.gradle(Module: app)に以下の依存関係を追加します。implementat
-
AndroidアプリでSQLiteデータベースを使う方法を徹底解説【CRUD実装の手順】
この記事では、AndroidアプリケーションでSQLiteデータベースを活用する方法を、実際のコード例とともに段階的に解説します。データの追加・一覧表示・更新・削除(CRUD操作)をすべて網羅したサンプルアプリを作成しながら、SQLiteの基本的な使い方をマスターしましょう。全体の流れ本チュートリアルでは、サッカー選手の名前と所属国を管理するシンプルなアプリを題材にします。主な構成要素は以下の通りです。DatabaseHelper:SQLiteOpenHelperを継承し、データベースの作成・管理を行うクラスDataBaseManager:データの挿入・取得・更新・削除を担当するクラスMain