[3팀] Android와 SQLite 데이터베이스
이 글은 이것이 안드로이드다 with 코틀린(개정판)를 참고하여 작성하였습니다.
작성자 : 강다인
개발환경은 Windows, Android Studio입니다.
Android에서 기본적으로 제공되는 SQLite에 생성, 입력, 수정, 삭제, 조회 5가지 패턴이 중요하다.
우선 SQLite.kt에 SqliteHelper 클래스를 만든다.
만든 SqliteHelper 클래스에서 context, name, version을 갖는 SquliteOpenHelper를 사용해서 생성합니다.
class SquliteHelper(context: Context, name:String, version:Int): SQLiteOpenHelper(context,name,null,version) {
그리고 ctrl+i를 눌러서 implement합니다.
override fun onCreate(p0: SQLiteDatabase?) {}
override fun onUpgrade(p0: SQLiteDatabase?, p1: Int, p2: Int) {}
SquliteHelper를 호출했을 때 name이 없으면 onCreate를 name은 있고 version이 다르면 onUpgrade를 호출해줍니다. onCreate에 테이블 쿼리를 작성합니다. “create table +이름(columbs)”이 SQL에서 테이블을 만드는 문법입니다. 그리고 create를 실행합니다.
val create = "create table memo ('no' integer primary key, content text, datetime integer)"
db?.execSQL(create)
내부 메서드 중 onCreate() 메서드는 파라미터로 전달받은 name(파일명)과 일치하는 파일이 없을 때 호출된다.
onUpgrade() 메서드는 파라미터로 전달받은 version 과 가지고 있는 version 이 서로 다르면 호출된다.
SqliteHelper() 메인 액티비티에서 사용하기 위해서는 아래와 같은 과정을 거친다.
변수를 선언하고 클래스 sqliteHelper() 를 그대로 선언하여 데이터베이스 파일을 생성한다.
데이터 베이스를 위한 네 가지 함수는 insert, select, delete, update이다.
> insert
데이터 입력 함수. 이때 insert 함수의 파라미터로 사용될 데이터를 위한 클래스를 선언해준다.
이는 코드를 간결하게 하기 위해서이다.
데이터베이스 파일에 insert 함수를 통해 넘겨받은 데이터를 넘겨준다.
이때 데이터는 ContetnValues 타입으로 지정되어 넘겨진다.
main 액티비티에서 호출하기 위해서는 해당 데이터의 클래스를 우선 선언하고 insert 함수를 호출한다.
어플을 재실행하더라도 insert 함수를 통해 데이터베이스 파일에 저장한 데이터는 그대로 유지된다.
> select
데이터 조회 함수. 전체를 모두 조회해보는 함수이기 때문에 Memo 타입의 데이터를 MutableList 를 반환하는 함수이다.
조회 함수의 쿼리문을 작성한다. 쿼리문의 경우, "select 조회할 대상 from 테이블명" 을 규칙으로 작성하는데,
조회할 대상이 모든 것이라면 * 로 표시한다.
Ex. val select = "select no, content, datetime from memo"
-> memo 테이블로 부터 no, content, datetime 컬럼을 조회하라
val select = "select * from memo"
-> memo 테이블로 부터 모든 컬럼을 조회하라
생성해놓은 데이터 베이스를 가져온다.
redableDatabase 를 불러온 후, 쿼리문을 실행시킨다. 조회함수 에서 쿼리문을 실행시키는 함수인 rawQuery() 의 반환값은 Cursor 타입이다. Cursor 는 데이터 베이스의 쿼리의 결과로 반환돤 데이터에서 현재 그 내용을 확인하고 있는 위치를 나타내는 정보를 의미한다.
데이터를 가져오는 작업완료후에는 cursor 와 db 를 닫아주고 list 를 반환한다.
> update
데이터 수정함수. 수정하기 위해서 writabledb 를 꺼낸다.
update 도 insert 와 마찬가지로 업데이트 하는 데이터를 ContentValues 타입으로 반환한다.
update 함수의 whereClause 에는 주로 유일한 데이터는 프라이머리 키가 들어간다.
이 부분이 수정할 부분을 나타내는 조건이 된다.
> delete
데이터 삭제함수. delete 쿼리를 작성한다. 이때 쿼리문은 "delete from 테이블명 where 조건" 의 형식이다.
이후 해당 쿼리문을 실행시키기 위한 db를 불러오고, 쿼리문을 실행시키는 함수 exeSQL() 를 작성한다. 데이터 삭제가 완료되면 불러왔던 db를 닫는다.
쿼리를 작성하는 대신, delete() 함수를 사용하여 특정 데이터를 삭제할 수 있다.
이때 테이블명과 whereClause 라는 조건을 잘 작성해주면 된다. 아래는 서로 대체가능한 식이다.
다음으로, 화면을 생성하고 SQLite로 구성한 데이터베이스를 사용해보겠다.
(1) 화면 구성
ConstraintLayout 화면에 PlainText 와 Button 을 하나식 삽입하여 constraint 연결한다.
텍스트와 버튼을 하단에 배치하고 상단에는 목록을 위한 RecyclerView 를 배치한다.
목록을 구성하는 item_recycler 라는 레이아웃 파일을 생성하고 구성한다.
main 레이아웃의 recycler 의 속성 중 listitem 에 생성해둔 item 리사이클러를 연결하여 미리보기를 할 수 있다.
리사이클러뷰가 사용할 어댑터를 생성하고 구성한다.
package com.example.sqlite
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import java.text.SimpleDateFormat
//import kotlinx.android.synthetic.main.item_recycler.view.*
class RecyclerAdapter : RecyclerView.Adapter<Holder>() {
var listData = mutableListOf<Memo>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_recycler, parent, false)
}
override fun onBindViewHolder(holder: Holder, position: Int) {
val memo = listData.get(position)
holder.setMemo(memo)
}
override fun getItemCount(): Int {
return listData.size
}
}
class Holder(itemView: View) : RecyclerView.ViewHolder(itemView){
fun setMemo(memo: Memo){
itemView.textNo.text = "${memo.no}"
itemView.textContent.text = "${memo.content}"
val sdf = SimpleDateFormat("yyyy/mm/dd hh:mm")
val datetime = sdf.format(memo.datetime)
itemView.textDatetime.text = "$datetime"
}
}
recyclerview의 holder 클래스와 adapter를 설정해주었다.
다음으로 MainActivity에 연결해준다.
class MainActivity : AppCompatActivity() {
val DB_NAME = "sqlite.sql"
val DB_VERSION = 1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val memo = Memo(1, "내용", 123123132)
val helper = SqliteHelper(this, DB_NAME, DB_VERSION)
val adapter = RecyclerAdapter()
// db에 있는 내용을 전부 listData에 넣기
val memos = helper.selectMemo()
adapter.listData.addAll(memos)
// recyclerView에 연결
recyclerMemo.adapter = adapter
recyclerMemo.layoutManager = LinearLayoutManager(this)
}
}
메모 입력 후 저장 → 데이터 베이스 저장 → 목록 갱신
button listener 연결
saveBtn.setOnClickListener {
val content = editMemo.text.toString()
if(content.isNotEmpty()){
val memo = Memo(null, content, System.currentTimeMillis())
helper.insertMemo(memo)
}
}
setOnClickListener 을 이용해서 db에 입력받은 memo를 insert한다. content에 editMemo에 입력한 내용을 받아오고, content가 비어있지 않으면 새 data memo를 생성해서 helper로 정의된 sqlite database에 insert 해준다.
실시간 반영 추가
입력한 내용이 실시간 반영될 수 있도록 코드를 추가하였다.
saveBtn.setOnClickListener {
val content = editMemo.text.toString()
Log.d("메모", "content = $content")
if(content.isNotEmpty()){
val memo = Memo(null, content, System.currentTimeMillis())
helper.insertMemo(memo)
// 기존 작성 글 삭제
editMemo.setText("")
// 목록 갱신
// 전체 삭제
adapter.listData.clear()
// 전부 다시 넣기
adapter.listData.addAll(helper.selectMemo())
adapter.notifyDataSetChanged()
}
}
editMemo에 남아있는 입력 내용 삭제 후, listData를 전체 삭제하고 db에서 다시 전부 불러다가 addAll 해준 뒤, Data가 바뀌었다는 것을 알리는 함수를 호출한다.