데이터는 Room을 사용하여 저장하였고, 등록하는 기능과 삭제하는 기능은 간단했다.
그런데 리사이클러뷰로 만들어진 뷰에 선택한 데이터만 삭제하려고 하니 걱정이 생겼다.
지금까지 Room을 통해서 데이터를 수정하기 위해선 viewModel이 필요했다.
// MainActivity에서 버튼을 클릭하면 뷰모델을 통해 데이터를 삭제하는 기능
binding.button.setOnClickListner {
viewModel.deleteAllToDoList()
}
그런데 리사이클러뷰에는 viewModel 객체가 없다. viewModel 객체를 생성자로 넘길까도 생각했지만 좋지 않은 패턴 같아서 그만뒀다.
Can I pass the ViewModel to a RecyclerView Adapter and observe a LiveData?
View models for RecyclerView items
그래서 찾아낸 방법이 고차함수로 Adapter에 db관련 메서드를 넘기는 것이었다.
package com.goodee.todolist
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.LiveData
import androidx.recyclerview.widget.RecyclerView
import com.goodee.todolist.database.ToDoList
import com.goodee.todolist.databinding.ItemTodolistBinding
class ToDoListAdapter(var toDoLists: LiveData<List<ToDoList>>,
private val doneTodoList: ((Int) -> Unit)? // 얘를 이용함
):
RecyclerView.Adapter<ToDoListAdapter.ViewHolder>() {
private val TAG: String = "로그"
inner class ViewHolder(binding: ItemTodolistBinding) : RecyclerView.ViewHolder(binding.root) {
val primaryKey = binding.textviewItemPrimarykey
val title = binding.textviewItemTitle
val content = binding.textviewItemContent
val isFinish = binding.checkboxItemIsfinish
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ToDoListAdapter.ViewHolder {
val binding = DataBindingUtil.inflate<ItemTodolistBinding>(LayoutInflater.from(parent.context),R.layout.item_todolist, parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ToDoListAdapter.ViewHolder, position: Int) {
val list: List<ToDoList>? = toDoLists.value
list?.apply {
holder.primaryKey.text = this.get(position).todolistPrimaryKey.toString()
holder.title.text = this.get(position).title
holder.content.text = this.get(position).content
holder.isFinish.isChecked = this.get(position).isFinish
}
holder.isFinish.setOnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
val deletedNo = holder.primaryKey.text.toString().toInt()
// 체크박스가 체크 되면 매개변수로 받은 doneTodoList가 콜백됨.
if (doneTodoList != null) {
doneTodoList.invoke(deletedNo)
}
}
}
}
override fun getItemCount(): Int {
Log.d(TAG,"ToDoListAdapter - getItemCount() called")
return toDoLists.value?.size ?: 0
}
}
액티비티에선 아래와 같이 매개변수를 넘겨줬다.
val toDoListAdapter = ToDoListAdapter(viewModel.toDoLists
,fun(primaryKey: Int) {
doneToDoList(primaryKey) // viewModel에 doneToDoList를 호출.
})
솔직히 이게 좋은 코드인지는 모르겠지만 내가 찾아본 답변 중에선 그나마 제일 나아 보인 방법 같다.
RxJava나 안드로이드에 대해 더 공부하면 수정 가능하지 않을까?
728x90
반응형