Android/Room
ROOM
${Harvey}
2022. 11. 22. 18:00
Room은 AAC(Android Architecture Components), 스마트폰 내장 DB에 데이터를 저장하기 쉽도록 해주는 라이브러리이다.(DB데이터를 Java or Kotlin 객체로 매핑 해준다.)
다양한 Annotation을 통해서 컴파일시 코드들을 자동 생성 해주고 SQLite와 달리 LiveData, RxJava와 같은 Obervation 형태를 지원 하고 MVP,MVVM과 같은 아키텍쳐 패턴에 쉽게 활용할 수 있도록 되어있다.
Room 라이브러리의 엔티티(Entity), 데이터 접근 객체(DAO),데이터 베이스(DB)의 상세 설명과 사용법은 구글 공식 문서에도 나와있지만 아래 블로그에서 많이 참고하였다.
Gradle.
plugins {
id 'kotlin-kapt'
}
// ROOM
def roomVersion = "2.4.0"
implementation("androidx.room:room-runtime:$roomVersion")
annotationProcessor("androidx.room:room-compiler:$roomVersion")
// To use Kotlin annotation processing tool (kapt)
kapt("androidx.room:room-compiler:$roomVersion")
// Coroutine, Room을 사용 할때 Coroutine을 사용해야함.
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
MainActivty.kt
// https://developer.android.com/training/data-storage/room?hl=ko
// https://developer.android.com/codelabs/android-room-with-a-view-kotlin?hl=ko#5
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val db = TextDataBase.getDatabase(this)
val inputArea = findViewById<EditText>(R.id.textInputArea)
val insertBtn = findViewById<Button>(R.id.insert)
val getAllBtn = findViewById<Button>(R.id.getData)
val deleteBtn = findViewById<Button>(R.id.delete)
insertBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
db.textDao().insert(TextEntity(0, inputArea.text.toString()))
inputArea.setText("")
}
}
getAllBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
Log.d("MAINACTIVITY", db.textDao().getAllData().toString())
}
}
deleteBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
db.textDao().deleteAllData()
}
}
}
}
Room과 Coroutine을 함께 사용하게 되면 DB 작업들은 UI 쓰레드가 아닌 디스패처에서 실행하게 된다. Room이어서가 아닌, Coroutine이어서 그렇다. suspend 함수는 다른 suspend 함수나 코루틴에서만 실행될 수 있다.
Dispatcher에 관한 문서: https://developer.android.com/kotlin/coroutines/coroutines-adv?hl=ko
TextDao.kt
@Dao
interface TextDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<TextEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : TextEntity)
@Query("DELETE FROM text_table")
fun deleteAllData()
}
TextEntitiy
@Entity(tableName = "text_table")
data class TextEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
TextDataBase.kt
@Database(entities = [TextEntity::class], version = 1)
abstract class TextDataBase : RoomDatabase(){
abstract fun textDao() : TextDao
companion object {
@Volatile
private var INSTANCE : TextDataBase? = null
fun getDatabase(
context : Context
) : TextDataBase {
return INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
TextDataBase::class.java,
"text_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
instance
}
}
}
}