

@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 {
}
@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)
}
@Database(entities = arrayOf(Todo::class), version = 1)
abstract class TodoDatabase: RoomDatabase() {
abstract fun todoDao() : TodoDao
}
Room.databaseBuilder().build()로 생성val db = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java, "database-name"
).build()
🍡 why repository?
- 사실 클론코딩한 예제에서 dao와 repository를 나누어서 사용해서 무작정 따라했다가 왜 나눴지?하고 찾아봤다.
- DAO : Data Access Object, DB에 접근하여 데이터를 조회하고 저장하는 역할. 일반적으로 DB 테이블 당 1:1 DAO 맵핑되어 해당 테이블에 대한 DB 작업을 DAO에서 수행
- Repository : 서비스 레이어에서 비즈니스 로직을 수행하는 필요한 데이터를 찾아서 반환하는 역할. 비즈니스 로직을 수행하는데 필요한 데이터를 여러개의 DAO에서 찾아올 수도 있고, 꼭 DAO를 사용하지 않고도 값을 셋팅해 보내야할 수도 있다. 서비스로 데이터를 반환할 때는 캡슐화가 되어야하고, 비즈니스 로직을 바로 수행할 수 있는 도메인 객체를 반환해야함.
(그러나 dao와 repository의 하는 일이 거의 같을 때에는 dao에서 바로 데이터를 보내도 된다.)
private const val DATABASE_NAME = "todo-databse.db"
class TodoRepository private constructor(context: Context){
private val database:TodoDatabase = Room.databaseBuilder(
context.applicationContext,
TodoDatabase::class.java,
DATABASE_NAME
).build()
// Dao 객체
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!")
}
}
}
DB -> DataBase -> DAO -> repository -> ViewModel의 여정을 거쳐서 앱에 보이게 되는 것이다!! 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)
}
}
// registerForActivityResult에서 투두 입력한 결과를 받아오는 부분
when(it.data?.getIntExtra("flag",-1)){
0 -> {
CoroutineScope(Dispatchers.IO).launch {
// todoViewModel.insert(todo)를 통해 viewModel -> todoRepository -> todoDao 순으로 타고 들어가 데이터베이스에 저장
todoViewModel.insert(todo)
}
Toast.makeText(this, "추가되었습니다.", Toast.LENGTH_SHORT).show()
}
...
} 2) 데이터 수정// 수정할 투두를 클릭했을 때
todoAdapter.setItemClickListener(object: TodoAdapter.ItemClickListener{
override fun onClick(view: View, position:Int, itemId: Long){
CoroutineScope(Dispatchers.IO).launch {
// itemId로 뷰모델에서부터 투두를 가져온다
val todo = todoViewModel.getOne(itemId)
val intent = Intent(this@MainActivity, EditTodoActivity::class.java).apply{
putExtra("type", "EDIT")
putExtra("item", todo )
}
requestActivity.launch(intent)
}
}
})// registerForActivityResult
...
1 -> {
CoroutineScope(Dispatchers.IO).launch {
todoViewModel.update(todo)
}
Toast.makeText(this, "수정되었습니다.", Toast.LENGTH_SHORT).show()
} 

https://jminie.tistory.com/171#2.%20%F0%9F%93%8C%C2%A0%20Room
https://gogumac.github.io/android/room/android-jetpack-room/
https://makemepositive.tistory.com/33
https://pekahblog.tistory.com/169