본문 바로가기
SW/개발

[Android/Kotlin] Todo List 앱을 만들어보자! - 3 (Room 데이터베이스)

by PEKAH 2021. 11. 16.

본 포스트는 Todo List 앱을 만들어보자! - 2 에 이어지는 글입니다.

 

이번 시간에는 Todo List의 데이터베이스 및 viewModel을 개발해보도록 하겠습니다.

 

이번에 생성할 파일들의 구조입니다.

각 기능별로 패키지를 세분화하였습니다. 

 

그럼 Todo DTO부터 만들어보겠습니다!

 

Todo.kt

@Entity(tableName = "todoTable")
class Todo(
    @ColumnInfo(name = "id") @PrimaryKey(autoGenerate = true) var id: Long = 0,
    @ColumnInfo(name = "title") val title: String,
    @ColumnInfo(name = "content") val content: String,
    @ColumnInfo(name = "timestamp") val timestamp: String,
    @ColumnInfo(name = "isChecked") var isChecked: Boolean
): Serializable {
}

- @Entitiy는 테이블 이름, @ColumnInfo는 컬럼에 들어갈 이름, @PrimaryKey는 기본키를 의미합니다.

- Todo

    - id: 기본키 autoGenerate = true 를 해주었기 때문에, id 값을 자동으로 증가하게 됩니다.

    - title: 제목

    - content: 내용

    - timestamp: 생성/수정 날짜

    - isChecked: 체크박스 클릭(할 일 완료) 여부

로 구성하였습니다.

- Intent에 객체를 담기 위해 Serializable을 상속받았습니다.

 

다음으로 Dao를 작성하겠습니다.

 

TodoDao.kt

@Dao
interface TodoDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insert(dto: Todo)

    @Query("select * from todoTable")
    fun list(): LiveData<MutableList<Todo>>

    @Query("select * from todoTable where id = (:id)")
    fun selectOne(id: Long): Todo

    @Update
    suspend fun update(dto: Todo)

    @Delete
    fun delete(dto: Todo)
}

- 액티비티 개발에 앞서 CRUD를 먼저 작성해두고 시작하겠습니다!

- insert, query, update, delete는 Room 어노테이션을 사용해 구성하였습니다. SQLite에 비해 훨씬 간편해진 것을 알 수 있을 것입니다.

- 모든 항목을 불러오는 list 함수의 경우 LiveData를 사용해, 추가, 수정, 삭제에 의해 변화하는 값에 대해 즉시 반영이 가능하도록 하였습니다.

 

이번에는 데이터베이스를 만들어보겠습니다.

 

TodoDatabase.kt

@Database(entities = arrayOf(Todo::class), version = 1)
abstract class TodoDatabase: RoomDatabase() {
    abstract fun todoDao(): TodoDao
}

- entity는 Todo 클래스로, RoomDatabase 라이브러리를 사용해 생성하였습니다.

 

다음으로 Repository를 만들어봅시다!

 

TodoRepository.kt

private const val DATABASE_NAME = "todo-database.db"
class TodoRepository private constructor(context: Context){

    private val database: TodoDatabase = Room.databaseBuilder(
        context.applicationContext,
        TodoDatabase::class.java,
        DATABASE_NAME
    ).build()

    private val todoDao = database.todoDao()

    fun list(): LiveData<MutableList<Todo>> = todoDao.list()

    fun getTodo(id: Long): Todo = todoDao.selectOne(id)

    fun insert(dto: Todo) = todoDao.insert(dto)

    suspend fun update(dto: Todo) = todoDao.update(dto)

    fun delete(dto: Todo) = todoDao.delete(dto)

    companion object {
        private var INSTANCE: TodoRepository?=null

        fun initialize(context: Context) {
            if (INSTANCE == null) {
                INSTANCE = TodoRepository(context)
            }
        }

        fun get(): TodoRepository {
            return INSTANCE ?:
            throw IllegalStateException("TodoRepository must be initialized")
        }
    }
}

- 먼저 Room.databaseBuilder().build() 를 통해 데이터베이스를 빌드하도록 합니다.

- companion object 객체는 클래스가 생성될 때 메모리에 적재되면서 동시에 생성하는 객체로, 데이터베이스 생성 및 초기화를 담당하기 위해 작성하였습니다.

 

다음으로 viewModel을 작성하겠습니다.

 

viewModel.kt

class TodoViewModel: ViewModel() {
    val todoList: LiveData<MutableList<Todo>>
    private val todoRepository: TodoRepository = TodoRepository.get()

    init {
        todoList = todoRepository.list()
    }

    fun getOne(id: Long) = todoRepository.getTodo(id)

    fun insert(dto: Todo) = viewModelScope.launch(Dispatchers.IO) {
        todoRepository.insert(dto)
    }

    fun update(dto: Todo) = viewModelScope.launch(Dispatchers.IO) {
        todoRepository.update(dto)
    }

    fun delete(dto: Todo) = viewModelScope.launch(Dispatchers.IO) {
        todoRepository.delete(dto)
    }

}

- viewModel은 액티비티의 라이프사이클과 별개로 돌아가기 때문에 데이터의 유지 및 공유가 가능합니다.

- 이에 따라 viewModel에서 CRUD를 사용해 액티비티의 이동이 있어도 동일하게 값을 불러올 수 있도록 하였습니다. 

 

마지막으로 ApplicationClass입니다!

 

ApplicationClass.kt

class ApplicationClass: Application() {

    override fun onCreate() {
        super.onCreate()

        TodoRepository.initialize(this)
    }
}

- 이 클래스의 경우 앱이 실행될 때 단 한번 실행되도록 하기 위해 작성하였습니다. 

- 앱 실행과 동시에 Repository 초기화를 통해 데이터베이스가 없을 경우 새로 빌드하도록 하였습니다.

 

ApplicationClass가 동작하도록 하기위해 Manifests를 수정하겠습니다.

 

AndroidManifest.xml

<application
    android:name=".config.ApplicationClass"
    ...
</application>

 

작성할 코드가 많았지만 충분히 따라올 수 있을 것이라 생각합니다!

 

오늘은 Room 데이터베이스, ViewModel 을 통해 CRUD 함수를 개발하였습니다.

 

다음시간에는 본격적으로 Todo 생성을 해보도록 하겠습니다.!

 

 

 

댓글