[Android] Recycler View, View Model 데이터 수정, 삭제 + 개발일지

 

[개발 일지]

 

<Kotlin으로 개발하는 한 달 일정 관리 앱 개발>

 

필요 기능! 

 

1. 일정 완료 시 데이터 수정하기 (isDone  =True 변경)

2. 일정 삭제하기 ( Model, Recycler View 내부 데이터 삭제)

3. 변경사항 반영 

 

먼저 ViewModel 내부에 데이터 수정과 삭제 함수를 수정했다.

 

fun delTodoData(key:String,todo:Todo){
    todoData[key]?.remove(todo)
    recentlyAddData.value = todoData
}

fun doneData(todo:Todo){
    todo.isDone = !todo.isDone
    recentlyAddData.value = todoData
}

 

delTodoData는 날짜를 key 값으로 가지는 Data들에 접근해서 원하는 데이터를 삭제하는 기능을 한다.

해당 키 값의 데이터가 null이 아니라면 사용자 요청으로 넘어온 todo 데이터를 삭제한다. 

 

doneData는 사용자 요청으로 넘어온 todo 데이터를 수정해준다. 

해당 todo 데이터에서 isDone (Todo 하였는지 : Boolean)이 True라면 False로 False라면 True로 변경한다.

 

fun delTodoData(key:String,todo:Todo){
    todoData[key]?.remove(todo)
    recentlyAddData.value = todoData
}

fun doneData(todo:Todo){
    todo.isDone = !todo.isDone
    recentlyAddData.value = todoData
}

 

delTodoData 함수는 key와 todo Data 모델을 받아와서 key값에 해당하는 Data가 있다면 삭제한다.

 

doneData 함수는 todo Data 모델을 받아와서 해당 데이터의 isDone (Boolean)을 수정한다.

사용자 요청에 따라 isDone이 True라면 False, False라면 True로 변경한다.

 

두 함수는 데이터를 수정, 삭제한 후에 LiveData인 recentlyAddData를 최신 값으로 갱신한다.

 

작성한 함수들을 Fragment 내부의 Recycler View의 Item에서 동작하게 해야한다.

Recycler View와 연결 된 adapter의 수정이 필요했다.

 

class ToDoCalendarAdapter(
    private val mainActivity : MainActivity,
    private var dataSet: ArrayList<Todo>,
    val onClickDeleteButton:(todo: Todo)->Unit,
    val onClickItem : (todo:Todo)->Unit,
    //return 값이 없는 Unit을 넘겨줌 외부로 position 넘겨주는 동작

 

adapter에 파라미터로 onClickDeleteButton과 onClickItem을 추가했다.

이들은 return 값이 없는 Unit을 값으로 넘겨줌으로써 외부로

어떤 item position의 데이터가  클릭 되었는지 알려주는 동작을 한다.

 

onClickDeleteButton은 삭제 버튼 클릭 시 해당하는 데이터를 삭제하는 동작을 하게하고,

onClickItem은 해당 item을 클릭 시 데이터를 수정(앞에서 작성한 isDone 변경)해준다.

 

 item 클릭과 관련 된 동작을 작성하기 위해서 onBindViewHolder 내부에 코드를 작성한다.

 

//onClickItem : unit = position 보내주기
holder.binding.calendarItemText.setOnClickListener {
    onClickItem.invoke(dataSet[position])
}

 

//삭제
holder.binding.calendarItemDel.setOnClickListener {
    onClickDeleteButton.invoke(dataSet[position])
}

 

두 가지 코드를 작성했다.

invoke 함수는 부르다라는 뜻으로 앞서 작성한 Unit 이벤트를 호출해서 외부로 해당 position의 데이터를 내보내준다.

이제 외부(Recycler View가 포함된 Fragment)에서 해당 데이터를 처리해야 한다.

 

recycler view와 adapter를 연결할 때 해당 동작을 작성해준다.

 

adapter = ToDoCalendarAdapter(
    mainActivity,
    keyData,
    onClickDeleteButton = {
        mainActivity.viewModel.delTodoData(keyDay, it)
    },
    onClickItem = {
        mainActivity.viewModel.doneData(it)
    },
)

 

Recycler View에서 invoke로 호출 된 값이 넘어오면 이전에 viewModel에서 작성한 함수들을 실행한다.

이후에 observe(LIveData를 감시)하는 부분에서 Recycler View의 데이터도 수정해준다.

 

mainActivity.viewModel.recentlyAddData.observe(mainActivity, Observer {
    it[keyDay]?.let { keyData ->
        (recentlyListRecycler.adapter as ToDoCalendarAdapter).setData(keyData)
    }
})

 

fun setData(newData:ArrayList<Todo>){
    dataSet = newData
    notifyDataSetChanged()
}

Recycler View 내부의 setData 함수를 실행해서 Recycler View를 초기화 해주었다.

이로써 LiveData와 Recycler View 데이터 모두 갱신에 성공했다.

 

[문제점] 

 

문제는 notifyDataSetChanged()의 사용이다.

Recycler View의 데이터를 수정할 때 모든 데이터를 건드리는 것을 조심하라는 글을 읽은 적이 있다.

하나의 데이터가 추가될 때 모든 데이터를 갱신하는 것을 피하라는 것 같다.

간단하게 생각해 봐도 하나의 데이터를 추가하기 위해 모든 데이터를 리셋하는 것은 비효율적이다.

다음에는 모든 데이터를 리셋하지 말고 새로 추가되거나 삭제된 데이터에 대해서만 변경을 적용해야 한다.