본문으로 바로가기

1. View 와 관련된 동작 (좋아요가 누르면 하트에 불이 들어오고, 다시 누르면 하트에 불이 사라짐)은

Binding 어댑터로 구현하였다.

2. 좋아요 수를 나타내는 것, 그리고 좋아요를 DB 에 송신하고 그걸 다시 수신하는 것은

Firebase의 ValueEventListener로 구현하였다.

 

좋아요에 관련된 데이터를 DB에서 송수신하는 것은 처음에는 Adapter 클래스 내부에서 정의하였다.

하지만 이는 바람직한 방향이 아님을 깨달았다. 어댑터에서 Network 통신과 관련된 작업을 하는 것은 MVVM에서 권장하는 구조가 아니기 때문이다.

이를 바람직한 구조로 변경하려면 어댑터 내에서 콜백을 호출하고 그 콜백을 Fragment에서 정의하는 것이다.

그런 식으로 바꾸어 정의해 사용한 결과, MVVM 구조에 맞게 좋아요 기능을 구현할 수 있었다.

 

좋아요 콜백 구현

class PokemonReviewsAdapter { 
	// 
 	fun interface LikeCallback {
        fun onClickLikeButton(Rposition: Int,itemdata:PokemonReviewsData?,likeview:ImageView)
    }
    //
}

@AndroidEntryPoint
class PokemonReviewsFragment : Fragment(),PokemonReviewsAdapter.LikeCallback{
//
    override fun onClickLikeButton(Rposition:Int,itemdata:PokemonReviewsData?,likeview:ImageView) {
        val user = loginviewmodel.getUser().value
        if(user != null){
            if(itemdata?.isLiked!!){
                viewmodel.setRemoveLike(pokemonname,user.uid,itemdata!!.uid!!)
            }else{
                viewmodel.setLikeTrue(pokemonname,user.uid,itemdata!!.uid!!)
            }
        }
    }
//
}

 

 

좋아요를 누르면 하트에 불이 들어오고, 다시 누르면 불이 꺼지는 View에 관한 처리를 처음에는 콜백 함수 내에서 Programatically 하게 컨트롤 하려 했다가 좋아요 상태에 관한 옵저빙을 뷰모델 클래스 내의 Firebase의 ValueEventListener 내에서 하고 있어 이 뷰를 어떻게 Programatically 하게 컨트롤 할 것인가가 문제가 되었다.

 

좋아요 상태에 관한 옵저빙을 담당하는 Viewmodel 클래스 내의 ValueEventListener

fun addReviewValueListener(pokemonname: String,query:String){ 
        viewModelScope.launch {
            val pokemonreviewref = repository.getQuery(pokemonname,query)
            when(pokemonreviewref){
                is Response.Success -> {
                    valueEventListener = object : ValueEventListener {
                        override fun onDataChange(snapshot: DataSnapshot) {
                            val reviewlist = ArrayList<PokemonReviewsData>()
                            for (ds in snapshot.children) {
                                val data = ds.getValue<PokemonReviewsData>()?: PokemonReviewsData()
                                if(auth.uid != null){
                                    val reported:Boolean = (ds.child("reporters").child(auth.uid!!).value?:false) as Boolean
                                    if(reported==false){
                                        reviewlist.add(data)
                                    }
                                    data.isLiked = (ds.child(Constants.QUERY_LIKES).child(auth.uid!!).value?: false) as Boolean
                                    data.likesnumber = ds.child(Constants.QUERY_LIKES).childrenCount.toInt() 
                                } else {
                                    reviewlist.add(data)
                                }
                                reviewdata.value = reviewlist.reversed()
                            }
                        }
                        override fun onCancelled(error: DatabaseError) {}
                    }
                    pokemonreviewref.data.addValueEventListener(valueEventListener)
                }
                is Response.Failure ->{
                    Log.d("InfoViewModel Query Error", "Query Error")
                }
            }
        }
    }

 

 

다소의 시행 착오를 거친 끝에, 리뷰의 데이터 클래스에 좋아요 상태에 관한 Boolean 변수를 하나 추가하여 BindingAdapter 를 활용하여 Databinding 으로 해결할 수 있었다.

View 에 관한 작업은 Databinding 을 활용하는 쪽으로 먼저 생각해야 한다는 것을 느끼게 된 작업이다.

 

BindingAdapter.kt

@BindingAdapter("isLiked")
fun bindIsLiked(view: ImageView, isLiked: Boolean?) {
    if (isLiked!!) {
        view.setImageResource(R.drawable.filled_heart)
    }else{
        view.setImageResource(R.drawable.heart)
    }
}