티스토리 뷰

728x90

 


Room

* 안드로이드에서 제공하는 데이터베이스 API

• 키-벨류 데이터베이스 : SharedPreferences

• 관계형 데이터베이스 : SQLite

     - but 공식문서에서는 SQLite API를 직접 사용하는 것이 아닌, Room 라이브러리를 이용하여 SQLite를 다루라고 권장한다.

 

* 서버 쪽에서만이 아닌 앱 쪽에서도 데이터를 저장할 수 있어야 하는 이유

• 캐싱이 가능하기 때문

     - 캐싱 : 캐시를 남기는 작업

     - 캐시 : 나중에 빠르게 다시 사용할 수 있도록 남기는 임시 데이터

     - 전에 사용했던 데이터를 다시 서버에 요청할 필요없이 빠르게 다시 사용할 수 있다.

     - 서버에만 데이터를 저장한다면 간단한 데이터라도 서버와 통신해야하기 때문에 효율이 떨어지고, 무겁다.

     - 네트워크 연결이 잠시 끊겨도 앱에 저장된 캐시로 앱을 계속해서 사용할 수 있다.

• Room은 관계형 데이터베이스이다. 대부분의 서버 데이터베이스들은 관계형 데이터베이스를 사용하기 때문에, 서버 쪽 데이터를 Room을 이용하여 캐싱하기에 좋다.

 

1. Room

• SQLite를 완벽히 활용하면서 원활한 데이터베이스 엑세스가 가능하도록 SQLite에 추상화 계층을 제공.

     -> SQLite를 더 편하게 사용할 수 있도록 Room이라는 계층이 하나 더 존재한다고 생각하면 된다.

     ex) 개발자가 Room에게 데이터 저장을 명령 -> Room이 SQLite를 이용하여 데이터를 저장해준다.

 

* 데이터베이스 작업은 메인 쓰레드에서 할 수 없다.

     - 데이터베이스 작업은 오래 걸리는 작업이 많은데, 메인 쓰레드에서 하게 되면, 작업을 하는 동안 사용자가 아무 것도 할 수 없기 때문.

     - 멀티 쓰레드를 이용하거나 Async를 이용한다.

 

Room을 사용하기 위해서는 앱의 build.gradle 파일에 다음을 추가해야 한다.

     - optional은 선택사항이다.

...생략...

apply plugin: 'kotlin-kapt'

...생략...

dependencies {
    ...생략...
    
    def room_version = "2.4.3"

    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version"

    // To use Kotlin annotation processing tool (kapt)
    kapt "androidx.room:room-compiler:$room_version"
    // To use Kotlin Symbol Processing (KSP)
    ksp "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.5.0-beta01"
}

 

 

• Entity, DAO(Data Access Object), Database를 정의한다.

     - 데이터베이스 이론이라 우선 간단히 알자.

     - Entity : 데이터베이스의 항목이라 생각하면 될 듯.

     - DAO : 데이터베이스에 엑세스하게 해주는 객체. DAO를 이용하여 데이터베이스에 데이터 추가, 수정, 삭제 등을 할 수 있다.

     - Database : 데이터베이스가 어떤 항목을 가질 지, 어떤 DAO를 이용할 지 정의

package com.example.fastcampus

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import androidx.room.*
import androidx.room.OnConflictStrategy.REPLACE

class Room_24 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_room24)

        val database = Room.databaseBuilder( // 데이터베이스 생성
            applicationContext,
            AppDatabase::class.java,
            "user_database").allowMainThreadQueries().build()

        findViewById<TextView>(R.id.save).setOnClickListener { // save 버튼을 누르면
            val user = User("홍", "길동") // 데이터 생성
            database.userDao().insert(user) // 데이터베이스에 데이터 추가
        }

        findViewById<TextView>(R.id.load).setOnClickListener { // load 버튼을 누르면
            val users = database.userDao().getAll() // 데이터베이스에 모든 항목 불러오기
            users.forEach {
                Log.d("testt", "" + it.id + " " + it.firstName + " " + it.lastName)
            }
        }

        findViewById<TextView>(R.id.delete).setOnClickListener { // delete 버튼을 누르면
            database.userDao().delete(1) // id = 1 인 데이터 삭제
        }
    }
}

@Database(entities = [User::class], version = 1) // 데이터베이스 선언
abstract class AppDatabase: RoomDatabase() {
    abstract fun userDao(): UserDao
}

@Dao // DAO 선언
interface UserDao {
    @Insert(onConflict = REPLACE)
    fun insert(user: User)

    @Query("DELETE FROM user WHERE id = :id")
    fun delete(id: Int)

    @Query("SELECT * FROM user")
    fun getAll(): List<User>
}

@Entity // Entity 선언
class User(
    @PrimaryKey(autoGenerate = true)
    val id: Int,

    @ColumnInfo(name = "last_name")
    val lastName: String,

    @ColumnInfo(name = "first_name")
    val firstName: String
    ) {
    constructor(lastName: String, firstName: String): this(0, lastName, firstName)
}

 

 

• activity_room24.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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"
    android:orientation="vertical"
    tools:context=".Room_24">

    <TextView
        android:id="@+id/save"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="#AAAAFF"
        android:gravity="center"
        android:text="save"
        android:textSize="50dp" />

    <TextView
        android:id="@+id/load"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="#FFAAAA"
        android:gravity="center"
        android:text="load"
        android:textSize="50dp" />

    <TextView
        android:id="@+id/delete"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="#AAFFAA"
        android:gravity="center"
        android:text="delete"
        android:textSize="50dp" />

</androidx.appcompat.widget.LinearLayoutCompat>

 

• 결과

save 3번(데이터베이스에 데이터 3개 추가) - load(Logcat에 출력) - delete(id가 1인 항목 삭제) - load(Logcat에 출력)

 

 

 

 

 

 

 

 

 

이 글은

패스트 캠퍼스 Android 앱 개발의 정석 with Kotlin 올인원 패키지 Online

강의를 듣고 공부한 내용을 바탕으로 작성되었습니다.

 


728x90
댓글
공지사항