Android Kotlin | Room DB의 사용법과 예제

임세현·2021년 12월 31일
4
post-thumbnail
post-custom-banner

What is?

Room은 스마스폰 내장 DB에 데이터를 저장하기 위해 사용하는 ORM(Object Relational Mapping) 라이브러리입니다. 쉽게 말해서. ROOM은 데이터베이스의 객체를 자바 or 코틀린의 객체로 매핑해주는 역할을 헙니다.

Room은 SQLite의 추상레이어 위에 제공하고 있으며 SQLite의 모든 기능을 제공하면서 편한 데이터베이스의 접근을 허용합니다.

Why?

ROOM과 SQLite 차이점은 다음과 같습니다.

  1. SQLite의 경우 쿼리에 대한 에러를 컴파일에 확인하는것이 없지만 ROOM에서는 컴파일 도중 SQL에 대한 유호성을 검사할 수 있습니다.

  2. Schemark 변경 될 경우 SQL쿼리를 수동으로 업데이트 해야하지만 ROOM은 쉽게 해결할 수 있습니다.

  3. SQLite은 Java또는 Kotlin의 객체를 변겨앟기 위해 상용구 코드(Boiler Plate code)를 사용해야하지만 Room의 경우 ORM(Object Relational Mapping) 덕분에 상용구 코드 없이 매핑이 가능합니다.

  4. Room의 경우 LiveData와 RxJava를 위한 Observation 으로 생성하여 동작할 수 있지만 SQLite는 그렇지 않습니다.

Room의 구조

Room은 3가지 구성요소(Database, Entity, Dao)로 구성되어 있습니다.

DataBase - 앱에 영구 저장되는 데이터와 기본 연결을 위한 주 액세스 지점
Entity - 데이터베이스 안의 테이블을 클래스로 나타낸 것
DAO(Database Access Object) - 데이터베이스에 접근하는데 사용되는 메소드들을 포함한다. (select, insert, delete... 등)

Room 사용해보기

  • 간단한 자동로그인 예제입니다.

gradle 설정

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"
}
  • 출처 : Android Developer

Entity 설정

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
}

DAO 설정

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)

}

Database 설정

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
        }
    }
}

MainActivity

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}")
            }
        }
    }
}

activity_main

<?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>
  • 위 코드를 모두 작성하고 실행하면 Room이 성공적으로 작동되는 것을 확인할 수 있습니다.

End

위에서 사용한 "자동로그인" 예제는 깃허브에 올려두었으며 참고하여 공부하시면 더 좋을 것 같습니다. 감사합니다.

profile
android developer
post-custom-banner

0개의 댓글