2024. 3. 9. 01:45ㆍ수업 복습!
오늘은 기존의 SQLiteDatabase가 아닌 RoomDatabase에 대해 배우게 되었습니다!
RoomDatabase란?
SQLiteDatabase 사용 시 프로그래밍을 보다 간단하게 할 수 있도록 제공되는 라이브러리로써
구글에서 정한 규격대로 프로그래밍을 하게 되면 SQLiteDatabase를 사용하는 코드를
자동으로 만들어준다!
1단계 : ViewBinding 세팅부터 해줍니다!
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
viewBinding = true
}
}
class MainActivity : AppCompatActivity() {
lateinit var activityMainBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(activityMainBinding.root)
}
}
2단계 : build.gradle.kts에 라이브러리를 설정 해줍니다
--> 상단 plugins에는 Kotlin("kapt")를 설정해주고
id("com.android.application")
id("org.jetbrains.kotlin.android")
kotlin("kapt")
}
--> 하단 plugins에는 implelmentation과 annotationProcessor, kapt를 설정 해줍니다
annotationProcessor("androidx.room:room-compiler:2.6.1")
kapt("androidx.room:room-compiler:2.6.1")
3단계 : Entity를 작성해줍니다
Entity는 데이터 베이스에 저장된 데이터를 담거나 저장할 데이터를 담을 모델에 해당합니다
RoomDatabase는 Entity에 작성한 내용을 기반으로 테이블을 생성해줍니다.
//tableName : 생성될 테이블의 이름
@Entity(tableName = "TestTable")
위의 코드처럼 @Entity를 활용하여 테이블을 생성해줍니다!
이후 컬럼으로 설정할 프러퍼티들을 주 생성자에 정의 합니다
//주 생성자에 정의한 프러퍼티들이 컬럼으로 만들어진다
data class TestModel (
//idx 컬럼
//autoGenerate에 true를 넣어주면 데이터를 저장할 때 마다 1씩 증가 되는
//값으로 채워준다
@PrimaryKey(autoGenerate = true)
var testIdx: Int = 0,
var testData1: String = "",
var testData2: Double = 0.0
)
4단계 : Dao를 작성해준다.
Dao는 DataBase Access Object의 약자로서
데이터 베이스에 접속해서 데이터를 읽고 쓰는 작업을 수행합니다!
--> TestDao라고 이름을 만들었습니다!
우선 TestDao를 인터페이스로 만들어 줍니다
interface TestDao {
}
데이터 저장
//매개 변수로 들어오는 모델 중에
//primary key로 지정된 프러퍼티는 1부터 1씩 증가되는 값으로 저장되고
//그 외에는 프러퍼티에 들어있는 값이 저장된다
// 예) insert into TestTable (testData1, testData2) values (?, ?)
@Insert
fun insertData(testModel: TestModel)
데이터 수정
//매개 변수로 들어오는 모델 중에
//primary key로 지정된 프로퍼티를 조건절로 하고
//그 외에는 프러퍼티에 들어있는 값으로 수정된다
// 예) update TestTable testData1 = ?, testData2 = ? where testIdx = ?
@Update
fun updateData(testModel: TestModel)
데이터 삭제
//매개 변수로 들어오는 모델의 프로퍼티 중에 primary key로 지정된 프로퍼티를 조건절로 하는
//쿼리문이 만들어진다
//예) delete from TestTable testIdx = ?
@Delete
fun deleteData(testModel: TestModel)
이 때 만약 자동으로 만들어지는 쿼리문이 아닌 다른 쿼리문을 쓰고자 한다면
Query라는 이노테이션을 이용합니다
데이터를 가져오는 것도 Query라는 이노테이션을 사용해야 합니다!
모든 행의 데이터를 다 가져오기
//반환 타입에 지정된 객체에 행의 데이터를 담아 전달해준다
@Query("select testIdx, testData1, testData2 from TestTable")
fun selectAllData():List<TestModel>●
행 하나의 데이터를 가져오기
//쿼리문에 값에 해당하는 부분은 매개변수의 이름을 지정한다
// :매개변수 이름
@Query("select testIdx, testData1, testData2 from TestTable where testIdx = :idx")
fun selectOneData(idx:Int) : TestModel
5단계 : DataBase를 작성해준다
SQLiteOpenHelper의 역할을 해준다고 생각하면 됩니다
추상 클래스로 만들어야 하고 이 클래스를 상속받아 필요한 기능들을 구현한 클래스가
자동으로 생성됩니다.
entity들을 정의해줍니다! 밑의 경우에는 Table이 하나라서 한 개만 적었지만
여러 개의 Table을 생성했을 경우 모두 적어줍니다!
@Database(entities = [TestModel::class], version = 1)
추상 클래스를 만들어 Dao를 지정해준다
//dao를 지정한다
abstract fun testDao() : TestDao
}
companion Object안에 데이터 베이스 객체를 담을 변수를 만들어준다
//데이터 베이스 객체를 담을 변수
var testDataBase:TestDatabase? = null
}
※여기서 잠깐!
RoomDatabase는 코루틴을 이용하게 됩니다.
즉 비동기적으로 동작할 수 있도록 되어 있습니다
하지만 비동기적 작업시 데이터 베이스 접속을 여러 군데에서 하면 문제가 발생할 수 있기 때문에
데이터 베이스 접속을 동기적으로 할 수 있도록 해야합니다!
fun getInstance(context: Context) : TestDatabase? {
if (testDataBase == null){
synchronized(TestDatabase::class.java){
//데이터 베이스를 생성하고 Model들의 구조와 동일한 테이블을 생성한다
// test.db : 접속할 SQLiteDatabase파일!
testDataBase = Room.databaseBuilder(
context.applicationContext, TestDatabase::class.java, "test.db"
).build()
}
}
return testDataBase
}
6단계 : MainActivity에서 구현해본다!
우선 제가 사용할 xml을 이렇게 구성했습니다
insert : 데이터를 저장한다
selectAll : 데이터를 전부 가져온다
selectOne : 지정한 데이터를 가져온다
update : 데이터를 수정한다
delete : 데이터를 삭제한다
# insert
//데이터를 저장한다
fun insertData(){
activityMainBinding.apply {
button.setOnClickListener {
//데이터 베이스에 접속한다
val testDataBase = TestDatabase.getInstance(this@MainActivity)
//저장할 데이터를 담는다
//primary key로 지정된 프러퍼티는 1부터 1씩 증가되는 값이 자동으로 부여되기 때문에
//이 프러퍼티는 제외한다
val testModel1 = TestModel1(testData1 = "문자열 1", testData2 = 11.11)
//저장한다
CoroutineScope(Dispatchers.Main).launch {
async (Dispatchers.IO){
testDataBase?.testDao()?.insertData(testModel1)
}
}
val testModel2 = TestModel1(testData1 = "문자열 2", testData2 = 22.22)
CoroutineScope(Dispatchers.Main).launch {
async (Dispatchers.IO){
testDataBase?.testDao()?.insertData(testModel2)
}
}
}
}
# selectAll
//모든 데이터를 가지고 온다
fun selectAllData(){
activityMainBinding.apply {
button2.setOnClickListener {
//데이터 베이스 접속
val testDatabase = TestDatabase.getInstance(this@MainActivity)
CoroutineScope(Dispatchers.Main).launch{
//데이터를 받아온다
val job1 = async(Dispatchers.IO){
testDatabase?.testDao()?.selectAllData()
}
val dataList = job1.await() as List<TestModel>
textView.text = ""
dataList.forEach {
textView.append("testIdx : ${it.testIdx}")
textView.append("testData1 : ${it.testData1}")
textView.append("testData2 : ${it.testData2}")
}
}
}
}
}
#selectOne
//한 개의 데이터를 가지고 온다
fun selectOneData(){
activityMainBinding.apply {
button3.setOnClickListener {
//데이터 베이스에 접속한다
val testDatabase = TestDatabase.getInstance(this@MainActivity)
CoroutineScope(Dispatchers.Main).launch {
//데이터를 받아온다
val job1 = async(Dispatchers.IO){
//여기서 1은 idx의 값을 의미한다
testDatabase?.testDao()?.selectOneData(1)
}
val testModel = job1.await() as TestModel
textView.text = ""
textView.append("testIdx : ${testModel.testIdx}\n")
textView.append("testData1 : ${testModel.testData1}\n")
textView.append("testData2 : ${testModel.testData2}\n")
}
}
}
}
# update
//데이터를 수정해준다
fun updateData(){
activityMainBinding.apply {
//데이터 베이스 접속
val testDatabase = TestDatabase.getInstance(this@MainActivity)
//데이터를 준비한다
//primary key인 textIdx가 조건절이 된다
val testModel = TestModel(testIdx = 1, testData1 = "새로운 문자열", testData2 = 55.55)
//수정한다
CoroutineScope(Dispatchers.Main).launch {
async(Dispatchers.IO) {
testDatabase?.testDao()?.updateData(testModel)
}
textView.text = "완료"
}
}
}
#delete
//데이터를 삭제해준다
fun deleteData(){
activityMainBinding.apply {
button5.setOnClickListener {
//데이터 베이스에 접근한다
val testDatabase = TestDatabase.getInstance(this@MainActivity)
//데이터를 준비한다
//primary key인 textIdx가 조건절이 된다
val testModel = TestModel(testIdx = 1)
//삭제한다
CoroutineScope(Dispatchers.Main).launch {
async(Dispatchers.IO){
testDatabase?.testDao()?.deleteData(testModel)
}
textView.text = "삭제 완료"
}
}
}
}
실행을 해보니 매우 잘 작동을 하였습니다!!
느낀점
지금까지 SQLiteDatabase만 사용해서 내부 저장소에 데이터를 저장했었는데
오늘 RoomDatabase를 활용하는 방법을 배우게 되어 좋았습니다
사실 멘토님과 멘토링을 하면서
요즘에는 SQLite보단 Room을 더 자주 쓴다고 말씀해주셨는데
SQLite만 사용할 줄 알다 보니
Room이란 무엇인지
왜 SQLite보단 Room을 더 자주 사용하는지
알 수 없었습니다..
하지만 오늘 드디어 RoomDatabase를 배우게 됨으로써
SQLiteDatabase를 사용하는 것보다
코드가 간결해진다는 걸 느낄 수 있었고
현재 제가 만들었던 프로젝트들의 내부 저장소를
SQLite에서 Room으로 바꿔보며 더욱 손에 익을 수 있도록
노력하겠습니다!
'수업 복습!' 카테고리의 다른 글
안드로이드 수업을 마치며 2탄! (0) | 2024.02.26 |
---|---|
안드로이드 수업을 마치며,,, (2) | 2024.02.24 |
왕초보 안드로이드 개발 11탄 (Menu, 메시지) (0) | 2024.01.31 |
왕초보 안드로이드 개발 10탄( 복습, parcelable, toolBar) (0) | 2024.01.30 |
왕초보 안드로이드 개발 9탄(Actitvity-2) (0) | 2024.01.28 |