마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

파이어베이스 삭제 시 무한반복

0 추천
holder.btn.setOnClickListener{ view ->

                Toast.makeText(view.context,"${memo.name} 버튼클릭!", Toast.LENGTH_SHORT).show()
                Log.v("커스텀어답터","${memo.name}발생")

                //리스트테스트에서 가져온것
                val data_array: MutableList<Data> = mutableListOf()
                Log.v("커스텀어답터","${database}발생1")
                database.addValueEventListener(object : ValueEventListener {
                    override fun onDataChange(dataSnapshot: DataSnapshot?) {
                        Log.v("커스텀어답터","${dataSnapshot}발생2")

                        database.child("list${memo}").setValue("${memo.name}")
                        Log.v("커스텀어답터","${memo.name} 저장완료")

                    }
                    override fun onCancelled(p0: DatabaseError?) {
                        println("Failed to read value.")
                    }
                })
                
        }

이런식으로 원래있던 리사이클러뷰에서 버튼을 누르면 다른 리사이클러뷰에 추가가되는 버튼을 만들어서 작동을합니다. 그리고 어플을 종료후 다시 켜면 추가한대로 잘 리사이클러뷰에 반영이 됩니다.

그리고 삭제버튼을 누르면 삭제가 잘됩니다.

근데 문제는 추가버튼으로 추가 후 어플을 종료하지않고 데이터를 추가한 리사이클러뷰에서 삭제버튼을 누르면 파이어베이스에 삭제랑 생성이 반복되면서 무한 증식으로 인해 파이어베이스가 멈추고 어플도 멈추는 문제가 생겼습니다. 오류를 해결하고 싶은데 어떻게 해야할지 모르겠네요....

 

아래는 삭제하는 버튼입니다.

override fun onBindViewHolder(holder: calendar_Holder, position: Int) {
        val memo = listData.get(position)
        holder.itemView.setOnClickListener { view ->
            Toast.makeText(view.context,"${memo} 아이템클릭!", Toast.LENGTH_SHORT).show()
        }
        //버튼클릭
        holder.btn.setOnClickListener{ view ->

            Toast.makeText(view.context,"${memo.name} 버튼클릭!", Toast.LENGTH_SHORT).show()
            Log.v("캘린더어답터","${memo.name}발생")

            //리스트테스트에서 가져온것
            Log.v("캘린더어답터","${database}발생1")
            database.addValueEventListener(object : ValueEventListener {
                override fun onDataChange(dataSnapshot: DataSnapshot?) {
                    Log.v("캘린더어답터","${dataSnapshot}발생2")
                        Log.v("캘린더어답터", "${memo.name}확인 중")
                            database.child("list${memo}").removeValue()
                            Log.v("캘린더어답터", "${memo.name} 삭제완료")


                }
                override fun onCancelled(p0: DatabaseError?) {
                    println("Failed to read value.")
                }
            })

        }
        holder.setData(memo)

    }
}

 

nagada32 (290 포인트) 님이 2021년 3월 28일 질문
왜 holder.btn.setOnlickListener가 두군데 있는 건가요? 같은 버튼 처럼 보이는데 하나는 추가이고 하나는 삭제인건가요? 이 부분이 이해가 안되네요.
위의 코드로는 파이어베이스 콜백이 두번 호출될 것 같은데요. 그리고 removeValue할 때마다 다시 콜백을 받을 것 같구요. 콜백안에서 database.child("list${memo}").removeValue() 하는게 아니라 이건 외부에서 처리해야 하는 동작 아닌가요?
네 리사이클러가 두개라서 추가랑 삭제 아이템도 나뉘게 만들고 그래서 어답터랑 뷰홀더도 나눠서 만들어 놓았는데 버튼함수에서 실행이 되도록 만든거였는데 그게 콜백안에서 이루어져서 문제였었나보네요.....

1개의 답변

+1 추천

파이어베이스의 콜백을 왜 어댑터나 뷰홀더에서 설정하시는지 이해가 안되네요. 해당 콜백은 데이터에 변경이 생기면 호출되는 걸로 보이는데, 그렇게 하시면 데이터에 변경이 생길 때 모든 뷰홀더에서 설정된 콜백들이 다 호출될 것 같은데요. 그리고 파이어베이스 노드를 추가하거나 삭제하는 부분도 콜백 안에서 하시면 안될 것 같은데요. 아래처럼 해보세요.

// Activity
// onCreate
super.onCreate(...)
database.addValueEventListener(object : ValueEventListener {
                    override fun onDataChange(dataSnapshot: DataSnapshot?) {
                        Log.v("커스텀어답터", "onDataChange")
                        updateAdapter()
 
                    }
                    override fun onCancelled(e: DatabaseError?) {
                        println("Firebase onCancelled: $e")
                    }
                })

adapter = FirebaseAdapter(getFirebaseItems())
adapter.onClicked { memo ->
     database.child("list${memo}").setValue("${memo.name}")
}
adapter.onDeleteItemClicked { memo ->
     database.child("list${memo}").removeValue()
}

recyclerView.adapter = adapter



private fun updateAdapter() {
    adapter.items = getFirebaseItems()
    recyclerView.post {
         adapter.notifyDatasetChanged()
    }
}

 //파이어베이스에 데이터를 가져오는 부분
private fun getFirebaseItems() {
    ...
}


// onDestroy
super.onDestroy()
adapter.onItemClicked = null
adapter.onDeleteItemClicked = null
recyclerView.adapter = null


// Adapter
var onItemClicked: ((Memo) -> Unit)? = null
var onDeleteItemClicked: ((Memo) -> Unit)? = null

override fun onBindViewHolder(holder: calendar_Holder, position: Int) {
        val memo = listData.get(position)
        holder.setData(memo)
        holder.itemView.setOnClickListener { view ->
            onItemClicked?.invoke(memo)
        }
        //버튼클릭
        holder.deleteBtn.setOnClickListener{ view -> 
            onDeleteItemClicked?.invoke(memo)
        }
    }
}

 

spark (227,470 포인트) 님이 2021년 3월 29일 답변
spark님이 2021년 3월 30일 수정
...