이번 포스팅은 RecyclerView에 이벤트 처리를 구현 할 것이다.
아이템을 클릭하면 Todo 아이템을 추가할 때 띄웠던 다이얼로그를 통해 Todo 아이템을 수정 할 것이다.
그리고 롱클릭을 통해 Todo 아이템을 삭제 해 보겠다.
- Interface 구현
class TodoListAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>() {
...
interface OnTodoItemClickListener {
fun onTodoItemClick(position: Int)
fun onTodoItemLongClick(position: Int)
}
var listener: OnTodoItemClickListener? = null
...
}
우선 어댑터의 상단에 위와 같은 코드를 작성한다.
아이템 클릭 인터페이스를 생성하고 아이템 클릭과 아이템 롱 클릭에 대하여 구현하게 할 것이고 외부에서 리스너를 통해 구현하게 된다.
- TodoListAdapter, ViewHolder 수정
class TodoListAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>() {
...
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_todo, parent, false)
val viewHolder = TodoViewHolder(view, listener)
return viewHolder
}
class TodoViewHolder(view: View, listener: OnTodoItemClickListener?): RecyclerView.ViewHolder(view) {
...
init {
view.setOnClickListener {
listener?.onTodoItemClick(adapterPosition)
}
view.setOnLongClickListener {
listener?.onTodoItemLongClick(adapterPosition)
return@setOnLongClickListener true
}
}
...
}
뷰홀더의 생성자에 리스너를 전달받도록 수정하고 뷰홀더 객체가 생성될 때 이 리스너를 통해 뷰에 리스너를 달아준다. 그리고 어댑터에서 뷰홀더를 생성할 때 이 리스너를 전달해준다.
- MainAcitivty 수정
class MainActivity : AppCompatActivity() {
...
private fun initRecyclerView() {
mTodoListAdater = TodoListAdapter().apply {
listener = object: TodoListAdapter.OnTodoItemClickListener {
override fun onTodoItemClick(position: Int) {
Toast.makeText(this@MainActivity, "onTodoItemClick!", Toast.LENGTH_SHORT).show()
}
override fun onTodoItemLongClick(position: Int) {
Toast.makeText(this@MainActivity, "onLongTodoItemClick!", Toast.LENGTH_SHORT).show()
}
}
}
...
}
...
}
TodoListAdapter를 apply 메서드를 통해 내부 블럭에서 listener에 접근하여 인터페이스를 구현 해 준다.
토스트 메시지를 통해 잘 동작하는지 확인 해 보았다.
한번 클릭했을 때 onTodoItemClick! 토스트가, 꾹 클릭했을 때 onLongTodoItemClick이 호출되면 성공이다.
- onTodoItemClick 처리 구현
private fun initRecyclerView() {
mTodoListAdater = TodoListAdapter().apply {
listener = object: TodoListAdapter.OnTodoItemClickListener {
override fun onTodoItemClick(position: Int) {
openModifyTodoDialog(getItem(position))
}
...
}
}
...
}
onTodoItemClick 메서드에서 포지션에 해당하는 TodoModel을 얻어오는 getItem(position: Int)를 호출한 뒤 얻어온 TodoModel을 openModifyTodoDialog 함수에 전달한다.
getItem은 TodoListAdaper에서 구현해야 한다. 간단한 코드이니 패스한다.
private fun openModifyTodoDialog(todoModel: TodoModel) {
val dialogView = layoutInflater.inflate(R.layout.dialog_add_todo, null)
dialogView.et_todo_title.setText(todoModel.title)
dialogView.et_todo_description.setText(todoModel.description)
val dialog = AlertDialog.Builder(this)
.setTitle("수정하기")
.setView(dialogView)
.setPositiveButton("확인", { dialogInterface, i ->
val title = dialogView.et_todo_title.text.toString()
val description = dialogView.et_todo_description.text.toString()
todoModel.description = description
todoModel.title = title
mTodoViewModel.updateTodo(todoModel)
})
.setNegativeButton("취소", null)
.create()
dialog.show()
}
전달받은 todoModel의 값으로 다이얼로그뷰의 텍스트들을 세팅한다.
그리고 다이얼로그를 통해 값을 받은 뒤 todoModel의 값을 변경하고 뷰모델의 updateTodo 함수에 전달한다.
class TodoViewModel(application: Application): AndroidViewModel(application) {
...
fun updateTodo(todoModel: TodoModel) {
mTodoRepository.updateTodo(todoModel)
}
...
}
class TodoRepository(application: Application) {
...
fun updateTodo(todoModel: TodoModel) {
Observable.just(todoModel)
.subscribeOn(Schedulers.io())
.subscribe({
mTodoDAO.updateTodo(todoModel)
}, {
// Handle error.
})
}
}
interface TodoDAO {
...
@Update
fun updateTodo(todoModel: TodoModel)
}
뷰모델, 리포지토리, DAO를 위와같이 변경한다. 매우 짧고 간단하다.
- onTodoItemLongClick 처리 구현
롱클릭을 하면 확인과 취소 버튼이 있는 다이얼로그를 출력하고 확인을 누르면 삭제하도록 구현 할 것이다.
private fun openDeleteTodoDialog(todoModel: TodoModel) {
val dialog = AlertDialog.Builder(this)
.setTitle("삭제하기")
.setMessage("확인을 누르면 삭제됩니다.")
.setPositiveButton("확인", { dialogInterface, i ->
mTodoViewModel.deleteTodo(todoModel)
})
.setNegativeButton("취소", null)
.create()
dialog.show()
}
기본 다이얼로그를 사용하여 위와 같은 함수를 MainAcitivty 내에 추가한다.
private fun initRecyclerView() {
mTodoListAdater = TodoListAdapter().apply {
listener = object: TodoListAdapter.OnTodoItemClickListener {
...
override fun onTodoItemLongClick(position: Int) {
openDeleteTodoDialog(getItem(position))
}
}
}
...
}
onTodoItemLongClick 메서드에서 위에서 추가한 다이얼로그 함수를 호출한다.
class TodoViewModel(application: Application): AndroidViewModel(application) {
...
fun deleteTodo(todoModel: TodoModel) {
mTodoRepository.deleteTodo(todoModel)
}
}
class TodoRepository(application: Application) {
...
fun deleteTodo(todoModel: TodoModel) {
Observable.just(todoModel)
.subscribeOn(Schedulers.io())
.subscribe({
mTodoDAO.deleteTodo(todoModel)
}, {
// Handle error.
})
}
}
interface TodoDAO {
...
@Delete
fun deleteTodo(todoModel: TodoModel)
}
위 처럼 뷰모델, 리포지토리, DAO를 수정한다.
굉장히 간단하게 이벤트를 추가하고 처리하는 기능을 구현하게 되었다.
- 다음 할 일
우선 지금까지 한 프로젝트에 문제가 있는데, update를 하고나서 리스트가 업데이트가 안된다는 것이다.
이유는 LiveData와 DiffUtil 때문인 것 같은데, 실제로 업데이트는 잘 이루어지지만 리스트 갱신이 되지 않고 있었다.
또한 예제이고 기능 사용에 중점을 뒀기 때문에 다이얼로그 쪽 코드가 중복이 많다.
심각한 문제는 아니기에 추후 수정으로 미루고, 다음으로는 DataBinding 이라는 것을 적용 볼 것이다.
'개발 > Android' 카테고리의 다른 글
[Android] Fragment로 Activity 구성 및 통신 - 2 (4) | 2020.05.23 |
---|---|
[Android] Fragment로 Activity 구성 및 통신 - 1 (0) | 2020.05.11 |
[Android] Kotlin + MVVM + AAC 로 Todo 앱 만들기 - 4 (0) | 2020.03.01 |
[Android] Kotlin + MVVM + AAC 로 Todo 앱 만들기 - 3 (0) | 2020.02.29 |
[Android] Kotlin + MVVM + AAC 로 Todo 앱 만들기 - 2 (3) | 2020.02.29 |