이 글은 이것이 안드로이드다 with 코틀린(개정판)를 참고하여 작성하였습니다.
작성자 : 임예람
개발환경은 Windows, Android Studio입니다.
1. Android와 SQLite 데이터 베이스
📌SQLite: 안드로이드에서 기본적으로 제공하는 데이터 베이스이다.
👉🏻SQLite를 사용해서 메모장을 만들어보자!
👉🏻SQLiteHelper: SQLite를 사용할 수 있는 도구가 되는 클래스
👉🏻메모장 테이블을 생성하는 onCreate와 메모장 변경사항을 저장하는 onUpgrade를 만든다.
👉🏻Main에서 sqliteHelper를 정의해준다.
✍🏻db 이름과 버전을 sqliteHelper 생성자로 넘겨주어 파일이 있는디 디렉토리를 찾는다. 없다면 onCreate 함수가 실행되어 memo 테이블을 생성한다.
👉🏻데이터 입력(메모 적는)함수
✍🏻wd: writableDatabase로 SQLiteOpenHelper에서 제공하는 데이터를 적는 기능이다.
👉🏻데이터 조회(메모 확인하는)함수
✍🏻rd: readableDatabase로 wd와 마찬가지로 SQLiteOpenHelper에서 제공하는 데이터를 읽는 기능이다.
👉🏻데이터 수정(메모 수정하는)함수와 데이터 삭제(메모 삭제하는)함수
✍🏻whereClause: 몇번째 데이터를 수정할지 위치를 정한다.
👉🏻SQLiteHelper에 메모 CRUD(메모 생성, 읽기, 수정, 삭제)를 모두 생성해둔다. 한 곳에 다 모아놨기 때문에 앞으로 Main에서는 데이터 처리할 때 helper만 바라보면 된다.
👉🏻이런식으로 리사이클러뷰로 메모 리스트를 표시하고 메모를 입력하고 저장할 버튼을 만든다.
👉🏻높이를 100dp로 설정한 아이템 하나의 항목 레이아웃을 만든다.
👉🏻아답터를 생성해 리사이클러에 데이터를 set하는 코드를 적는다.
✍🏻SimpleDateFormat: 어떠한 형식으로 날짜를 출력할지 지정한다.
👉🏻Holder와 Helper를 이용해 데이터를 넣어주고 출력하는 코드를 쓴다.
👉🏻Main에 아답터를 생성하고 메모를 적고 저장하는 코드를 짠다.
👉🏻Main에 버튼을 누르면 메모를 저장하는 코드를 작성한다.
2. Room 데이터베이스
📌Room: SQLite에 대한 추상화 레이어를 제공하여 원활한 데이터베이스 액세스를 지원하는 동시에 SQLite를 완벽히 활용한다.
📌상당한 양의 구조화된 데이터를 처리하는 앱은 데이터를 로컬로 유지하여 대단한 이점을 얻을 수 있다. (ex)관련 데이터를 캐싱하는 것) 이런 방식으로 기기가 네트워크에 액세스할 수 없을 때 오프라인 상태인 동안에도 사용자가 여전히 콘텐츠를 탐색할 수 있다. 나중에 기기가 다시 온라인 상태가 되면 사용자가 시작한 콘텐츠 변경사항이 서버에 동기화된다.
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
}
dependencies {
def roomVersion = "2.3.0"
implementation("androidx.room:room-runtime:$roomVersion")
annotationProcessor("androidx.room:room-compiler:$roomVersion")
kapt("androidx.room:room-compiler:$roomVersion")
implementation("androidx.room:room-ktx:$roomVersion")
...
}
👉🏻build.gradle에 다음과 같이 설정해준다.
//메모리스트를 받아와 각각 메서드를 실행
class RecyclerAdapter(val roomMemoList:List<RoomMemo>) : RecyclerView.Adapter<RecyclerAdapter.Holder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val binding = ItemRecyclerBinding.inflate(
//첫 인자는 context, 두번째는 부모 뷰
LayoutInflater.from(parent.context), parent, false)
return Holder(binding) //홀더에 바인딩을 넘겨준다.
}
override fun onBindViewHolder(holder: Holder, position: Int) {
//해당 메모 위치를 얻어와 set한다.
holder.setMemo(roomMemoList.get(position))
}
override fun getItemCount() = roomMemoList.size
//아답터는 항상 홀더를 가장 먼저 세팅
class Holder(binding: ItemRecyclerBinding) : RecyclerView.ViewHolder(binding.root) {
//메모 내용 set하는 함수
fun setMemo(roomMemo:RoomMemo) {
textNo.text = "${roomMemo.no}"
textContent.text = roomMemo.content
//Long 타입 숫자를 날짜로 변환
val sdf = SimpleDateFormat("yyyy/MM/dd hh:mm")
textDatetime.text = sdf.format(roomMemo.datetime)
}
}
}
👉🏻RecyclerAdapter에서 메모 내용을 set하는 코드를 짠다.
✍🏻항상 Holder를 먼저 세팅해준다.
//데이터는 테이블 형식으로 들어간다.
@Entity(tableName = "room_memo")
class RoomMemo {
//null이 들어가면 숫자를 자동으로 생성해주는 키
@PrimaryKey(autoGenerate = true)//no에 값이 없을 때 자동증가된 숫자값을 db에 입력해준다.
//메모에 쓸 변수 생성
@ColumnInfo //컬럼을 사용한다고 명시
var no: Long? = null
@ColumnInfo
var content: String = ""
@ColumnInfo(name = "date") //데이터베이스에는 date라는 이름으로 컬럼을 생성한다.
var datetime: Long = 0
//생성자를 사용해 내용과 날짜를 받는다. 편리하게 사용
constructor(content: String, datetime: Long) {
this.content = content
this.datetime = datetime
}
}
👉🏻RoomMemo 파일에서 메모 데이터 형식을 정해준다.
✍🏻@Entity: 기본적으로 Room은 클래스 이름을 데이터베이스 테이블 이름으로 사용한다. 테이블의 이름을 다르게 지정하려면 @Entity 주석의 tableName 속성을 설정해준다.
✍🏻@PrimaryKey: null 값이 들어오면 숫자를 자동으로 생성해준다. (Room에서 항목에 자동 ID를 할당한다.)
✍🏻@ColumnInfo: 컬럼을 사용한다고 명시해준다.
@Dao // dao임을 알려준다.
interface RoomMemoDAO {
//쿼리를 직접 짜준다.
@Query("select * from room_memo")
fun getAll() : List<RoomMemo>
//충돌이 나면 교체해준다.
@insert(onConflict = onConflictStrategy.REPLACE)
fun insert(memo:RoomMemo)
@delete
fun insert(memo:RoomMemo)
}
👉🏻RoomMemoDAO에서 세개의 메서드를 만들어 준다.
//데이터베이스임을 명시하고 내가 사용하는 데이터 개수와 버전을 넘겨준다.
@Database(entities = arrayOf(RoomMemo::class), version = 1, exportSchema = false)
//helper는 직접 사용할 수 있는 class가 아니므로 abstract이다.
abstract class RoomHelper : RoomDatabase() {
//룸 헬퍼를 통해 이 메서드를 호출하면 RoomMemoDAO 인터페이스가 반환된다.
//Dao에 있는 메서드를 꺼내 쓸 수 있다.
//room이 코드를 알아서 생성해주므로 간결하다!
abstract fun roomMemoDao(): RoomMemoDAO
}
👉🏻실제로 room을 사용할 Helper클래스를 만들어준다.
✍🏻helper는 직접 사용할 수 있는 class가 아니므로 abstract으로 선언한다.
✍🏻roomMemoDao를 지정하고 불러주기만 하면 room이 코드를 알아서 생성해준다. (굉장히 편리한 도구)
class MainActivity : AppCompatActivity() {
val binding by lazy{ ActivityMainBinding.inflate(layoutInflater)}
//room을 사용하기 위해 helper 선언
lateinit var helper:RoomHelper
//아답터 생성
lateinit var memoAdapter:RecyclerAdapter
//메모리스트 갱신
val memoList = mutableListOf<RoomMemo>()
//내가 쓰는 dao 꺼내놔서 사용
lateinit var memoDAO:RoomMemoDAO
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
//빌더가 호출되는 순간 룸 헬퍼를 사용할 수 있게 헬퍼 코드를 다 채우고 헬퍼 클래스를 만들어 전달
helper = Room.databaseBuilder(this, RoomHelper::class.java, "room_db")
.allowMainThreadQueries() //공부할 때만 쓴다.
.build()
memoDAO = helper.roomMemoDao()
//아답터를 이용해 목록을 보여준다.
memoAdapter = RecyclerAdapter(memoList)
//아래에 정의된 함수 - 변경 내용을 보여준다.
refreshAdapter()
with(binding) {
//아답터와 연결
recyclerMemo.adapter = memoAdapter
//with 스코프 내이기 때문에 어디 this인지 명시 필요
recyclerMemo.layoutManager = LinearLayoutManager(this@MainActivity)
buttonSave.setOnClickListener {
//메모 내용을 가져와서
val content = editMemo.text.toString()
//비어있지 않으면 내용을 헬퍼에 담아 넘겨준다.
if(content.isNotEmpty()) {
val datetime = System.currentTimeMillis()
val memo = RoomMemo(content, datetime)
memoDAO.insert(memo)
refreshAdapter()
}
}
}
}
//새로운 메모를 집어넣기
//기존 내용을 비우고 모든 데이터를 불러와 마지막에 바뀐 부분만 표시해 맨 마지막에 추가된 메모가 보임
//데이터가 많을 때는 사용하기 힘드니까 데이터가 적을 때 사용
fun refreshAdapter() {
memoList.clear()
memoList.addAll(memoDAO.getAll())
memoAdapter.notifyDataSetChanged()
}
}
👉🏻MainActivity에서 이전까지 만들었던 helper, adapter 등을 모두 정의해두고 코드를 적는다.
👉🏻메모를 업데이트 하는 내용의 코드는 자주 사용하므로 refreshAdapter 함수로 만들어 따로 빼둔다.
✍🏻refreshAdapter 함수의 내용을 보면 데이터 수정 내용을 반영하는 방식이 이전 데이터를 모두 지우고 모든 데이터를 불러와 바뀐 부분만 출력한다. 이 방법은 현재 데이터가 적기 때문에 사용할 수 있는 방식이고 이후 데이터 양이 많아지거나 정식으로 프로젝트 할 때는 사용하지 않는 것이 좋다.
'GDSC HUFS 3기 > Android with Kotlin Team 5' 카테고리의 다른 글
[5팀] 코틀린 안드로이드 기초강의_46~48 | 코루틴으로 이미지 불러오기, 서비스, 포그라운드 (0) | 2021.11.30 |
---|---|
[5팀] 코틀린 안드로이드 기초강의_43,44,45 | 카메라 원본 이미지, 갤러리, 쓰레드 타이머 (0) | 2021.11.30 |
[5팀] 코틀린 안드로이드 기초강의_39~40 | 파일 입출력, SharedPrefere (0) | 2021.11.23 |
[5팀] 코틀린 안드로이드 기초강의_31~32 | 프래그먼트 (0) | 2021.11.03 |
[5팀] 코틀린 안드로이드 기초강의_29~30 | 리사이클러뷰 (0) | 2021.11.03 |