Android에서 내부적으로 사용하는 가장 대표적인 DB로 SQLite가 있습니다. 경량화된 DB이기도 하고 성능도 꽤나 잘 나오기 때문에 모바일뿐만이 아니라 여러 가지 용도의 앱이나 프로그램 등에서 내부 데이터 저장용으로 많이 사용되는 DB입니다.
이 SQLite를 다루기 위한 헬퍼 클래스를 작성해 볼 텐데 우선 어떤 사람의 이름과 전화번호를 기록하는 앱을 만들어야 한다고 가정해 보겠습니다. 앱 입장에서는 이름, 전화번호를 기억하는 용도로 SQLite를 사용하기로 했는데 그러려면 우선 DB에 접속하는 단계가 필요하고 이후에 정보를 담아둘 최소 단위인 테이블을 생성해야 합니다. 물론 테이블은 한번 만들어 두면 다시 생성하지 않아도 됩니다.
이후에 필요한 정보를 가져오거나 추가 또는 변경, 삭제하는 동작을 하게 되고 마지막으로 필요한 적업을 모두 진행하였으면 DB와의 연결을 끊는 것으로 마무리해야 합니다. 연결을 끊지 않으면 자원이 불필요하게 낭비되기 때문입니다.
이러한 일련의 과정을 구현하는데는 여러 가지 방법이 있겠지만 대부분 중간에 DB(SQLite)와 처리를 담당하는 Helper 클래스를 만들어 두고 앱과 DB사이에 중간다리 역할을 하게 하는 것이 보통이므로 해당 클래스를 작성해 보도록 하겠습니다.
app -> java -> [패키지명]에서 마우스 오른쪽 버튼을 눌러 New -> Kotlin File/Class를 선택합니다.
이어지는 화면에서 Class를 선택 후 파일명에 SQLiteHelper를 입력하고 OK를 눌러줍니다.
Class파일이 생성되면 다음과 같이 SQLiteOpenHelper클래스를 상속받도록 합니다. SQLiteOpenHelper는 Context, DB명, 팩토리, 버전을 생성자의 매개변수로 받는데 팩토리만 null로 처리하고 나머지는 SQLiteHelper의 생성자로 받아 SQLiteOpenHelper의 생성자 쪽으로 넘겨줄 수 있도록 합니다.
package com.example.myapplication
import android.content.Context
import android.database.sqlite.SQLiteOpenHelper
class SQLiteHelper(context: Context, DB: String, version: Int) : SQLiteOpenHelper(context, DB, null, version) {
}
그런 후 Class안쪽에서 Ctrl + I 키를 눌러 나오는 모든 목록을 선택하고 OK를 눌러 주세요.
TODO를 모두 삭제하고 onCreate에서 필요한 Table을 생성하는 구문을 추가합니다. onCreate는 SQLiteHelper클래스 실행 시 DB가 생성되지 않은 최초 시점에 호출되는데, DB는 SQLiteOpenHelper에서 생성자를 받아 실행될 때 매개변수로 전달한 이름으로 생성됩니다. onCreate는 DB가 생성되어 있으면 더 이상 호출되지 않습니다.
override fun onCreate(db: SQLiteDatabase?) {
val PBTable = "Create Table phoneBook (" +
"seq integer primary key, " +
"name text, " +
"phone text)"
db?.execSQL(PBTable)
}
예제에서 테이블의 이름은 phoneBook로 하였으며 정수형 seq 컬럼을 만들고 이것을 key로 잡았습니다. 그리고 이름을 저장하는 name컬럼, 전화번호를 저장하는 phone컬럼을 text형으로 생성합니다.
onUpgrade는 매개변수로 전달되는 version값이 다른 경우에 호출되며 버전에 따라 변경되는 사항을 처리할 때 사용됩니다. 현재 예제에서는 사용하지 않습니다.
위에서 테이블을 생성하였으면 이제 테이블을 대상으로 데이터를 추가, 삭제, 변경, 조회하는 각각의 메서드를 구현해야 합니다. 이를 위해 테이블을 하나의 데이터 클래스로 표현하는 것부터 시작합니다.
SQLite에서 integer로 정의한 seq는 Kotlin에서 Long으로 정의합니다. integer의 표현 범위가 서로 다르기에 똑같이 integer로 정의하면 숫자가 커질 경우 문제가 생길 수 있기 때문입니다. 또한 seq를 받을때 ?를 붙여 값을 받지 않는 경우도 고려했습니다. seq는 primary key이므로 값이 자동 증가 형태라 데이터를 삽입(insert)하는 경우 seq값을 필요로 하지 않기 때문입니다.
data class PhoneBook(var seq: Long?, var name: String, var phone: String)
이제 SQLiteHelper클래스 안에서 데이터를 추가하는 메서드를 작성합니다. 데이터는 ContentValues()로 정의하고 SQLiteHelper안에 구현된 writableDatabase를 통해 값을 저장합니다. 저장 이후에는 반드시 마지막에 close()를 호출해 db연결을 닫아야 합니다.
fun addPhoneBook(pb: PhoneBook) {
val v = ContentValues()
v.put("name", pb.name)
v.put("phone", pb.phone)
val db = writableDatabase
db.insert("phonebook", null, v)
db.close()
}
데이터를 추가했으면 추가한 데이터를 확인할 수 있는 select를 구현합니다.
먼저 쿼리를 작성해 DB안에서 모든 데이터를 가져올 수 있도록 합니다. cursor를 통해 지정한 query를 주면 그에 맞는 데이터를 순차적으로 가져오게 되는데, 이걸 순회하여 각 컬럼의 데이터를 변수에 담고 그걸 다시 list에 담는 것을 반복합니다. 그리고 마지막에 cursor와 db를 닫고 데이터를 담은 list를 넘겨주면 됩니다. 또한 읽을 때의 db는 readableDatabase로 지정함에 주의합니다.
fun getPhoneBook(): MutableList<PhoneBook> {
val pbList = mutableListOf<PhoneBook>()
val query = "Select seq, name, phone From phoneBook"
val db = readableDatabase
val cursor = db.rawQuery(query, null)
while(cursor.moveToNext()) {
val seq = cursor.getLong(cursor.getColumnIndex("seq"))
val name = cursor.getString(cursor.getColumnIndex("name"))
val phone = cursor.getString(cursor.getColumnIndex("phone"))
pbList.add(PhoneBook(seq, name, phone))
}
cursor.close()
db.close()
return pbList
}
데이터를 추가하는 것 이외에 이미 추가된 데이터를 변경할 수도 있어야 할 것입니다. 데이터 변경은 삽입과 비슷하지만 primary key값을 통해 어떤 데이터를 변경해야 하는지를 알려줘야 합니다.
fun modifyPhoneBook(pb: PhoneBook) {
val v = ContentValues()
v.put("name", pb.name)
v.put("phone", pb.phone)
val db = writableDatabase
db.update("phoneBook", v, "seq = ${pb.seq}", null)
db.close()
}
마지막으로 손절한 사람은 삭제할 수 있는 기능을 구현합니다. 삭제는 데이터를 수정하는 경우와 비슷하지만 별도로 데이터를 받아서 처리하는 부분이 필요 없기에 primary key만으로 데이터를 삭제합니다.
fun removePhoneBook(pb: PhoneBook) {
val db = writableDatabase
db.delete("phoneBook", "seq = ${pb.seq}", null)
db.close()
}
참고로 위에서 구현한 modifyPhoneBook()과 removePhoneBook()는 모두 아래와 같이 query로도 구현이 가능합니다.
fun removePhoneBook(pb: PhoneBook) {
val query = "Delete From phoneBook where seq = ${pb.seq}"
val db = writableDatabase
db.execSQL(query)
db.close()
}
이것으로 SQLHelper가 대략적으로 완성되었습니다.
'Mobile > Kotlin' 카테고리의 다른 글
[kotlin] ORM라이브러리 Room (0) | 2020.12.30 |
---|---|
[kotlin] SQLite - 연결및 사용하기 (0) | 2020.12.30 |
[kotlin] androidx.preference (0) | 2020.12.28 |
[kotlin] Preferences (0) | 2020.12.28 |
[kotlin] 저장소및 파일처리 (0) | 2020.12.24 |