Room은 스마스폰 내장 DB에 데이터를 저장하기 위해 사용하는 ORM(Object Relational Mapping) 라이브러리입니다. 쉽게 말해서. ROOM은 데이터베이스의 객체를 자바 or 코틀린의 객체로 매핑해주는 역할을 헙니다.
Room은 SQLite의 추상레이어 위에 제공하고 있으며 SQLite의 모든 기능을 제공하면서 편한 데이터베이스의 접근을 허용합니다.
ROOM과 SQLite 차이점은 다음과 같습니다.
SQLite의 경우 쿼리에 대한 에러를 컴파일에 확인하는것이 없지만 ROOM에서는 컴파일 도중 SQL에 대한 유호성을 검사할 수 있습니다.
Schemark 변경 될 경우 SQL쿼리를 수동으로 업데이트 해야하지만 ROOM은 쉽게 해결할 수 있습니다.
SQLite은 Java또는 Kotlin의 객체를 변겨앟기 위해 상용구 코드(Boiler Plate code)를 사용해야하지만 Room의 경우 ORM(Object Relational Mapping) 덕분에 상용구 코드 없이 매핑이 가능합니다.
Room의 경우 LiveData와 RxJava를 위한 Observation 으로 생성하여 동작할 수 있지만 SQLite는 그렇지 않습니다.
Room은 3가지 구성요소(Database, Entity, Dao)로 구성되어 있습니다.
DataBase - 앱에 영구 저장되는 데이터와 기본 연결을 위한 주 액세스 지점
Entity - 데이터베이스 안의 테이블을 클래스로 나타낸 것
DAO(Database Access Object) - 데이터베이스에 접근하는데 사용되는 메소드들을 포함한다. (select, insert, delete... 등)
dependencies {
def room_version = "2.3.0"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
// optional - RxJava2 support for Room
implementation "androidx.room:room-rxjava2:$room_version"
// optional - RxJava3 support for Room
implementation "androidx.room:room-rxjava3:$room_version"
// optional - Guava support for Room, including Optional and ListenableFuture
implementation "androidx.room:room-guava:$room_version"
// optional - Test helpers
testImplementation "androidx.room:room-testing:$room_version"
// optional - Paging 3 Integration
implementation "androidx.room:room-paging:2.4.0-rc01"
}
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.PipedWriter
@Entity
data class LoginEntity(
val username: String,
val password: String
) {
@PrimaryKey(autoGenerate = true) var id: Int = 0
}
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
@Dao
interface LoginDao {
@Query("Select * From LoginEntity")
fun getLogin() : LoginEntity
@Query("DELETE From LoginEntity")
fun deleteLogin()
@Insert
fun insetLogin(loginEntity: LoginEntity)
}
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database(
entities = [LoginEntity::class],
version = 1,
exportSchema = false
)
abstract class LoginDatabase: RoomDatabase() {
abstract fun loginDao() : LoginDao
companion object {
private var instance: LoginDatabase? = null
@Synchronized
fun getInstance(context: Context): LoginDatabase? {
if (instance == null) {
synchronized(LoginDatabase::class) {
instance = Room.databaseBuilder(
context.applicationContext,
LoginDatabase::class.java,
"login-database"
)
.build()
}
}
return instance
}
}
}
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.saehyun.roomexample.database.LoginEntity
import com.saehyun.roomexample.database.LoginDatabase
import com.saehyun.roomexample.databinding.ActivityMainBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var db: LoginDatabase
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
db = LoginDatabase.getInstance(applicationContext)!!
refreshLogin()
binding.btn.setOnClickListener {
addLogin()
refreshLogin()
startLogin()
}
}
private fun startLogin() {
startActivity(Intent(applicationContext, SuccessActivity::class.java))
}
private fun addLogin() {
val username = binding.etID.text.toString()
val password = binding.etPW.text.toString()
CoroutineScope(Dispatchers.IO).launch {
db.loginDao().insetLogin(LoginEntity(username, password))
}
}
private fun refreshLogin() {
CoroutineScope(Dispatchers.Main).launch {
val data = CoroutineScope(Dispatchers.IO).async {
db.loginDao().getLogin()
}.await()
if(data != null) {
binding.etID.setText("${data.username}")
binding.etPW.setText("${data.password}")
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="104dp"
android:text="AutoLogin"
android:textSize="24dp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:hint="ID"
android:paddingLeft="24dp"
android:id="@+id/etID"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="52dp"
android:layout_marginEnd="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
<EditText
android:hint="PW"
android:paddingLeft="24dp"
android:id="@+id/etPW"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etID" />
<Button
android:id="@+id/btn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="LOGIN"
app:layout_constraintEnd_toEndOf="@+id/etPW"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="@+id/etPW"
app:layout_constraintTop_toBottomOf="@+id/etPW" />
</androidx.constraintlayout.widget.ConstraintLayout>
위에서 사용한 "자동로그인" 예제는 깃허브에 올려두었으며 참고하여 공부하시면 더 좋을 것 같습니다. 감사합니다.