在kotlin中firebase Documentlistener在该方法中调用时多次调用onBindViewHolder方法(无限调用)

问题描述 投票:0回答:1

这是 Reyclerview 的适配器类 我的问题是,当我在 onBindViewHolder 方法中调用 firebase 文档时,由于 addSnapshotListener 的回调,它会调用无限循环,因为当 firebase 添加快照 Litener 并设置为特定文本视图时,我需要立即反映数据。我已经在我的旧项目上工作正常,但现在它不起作用。

package com.wedoapps.cricketLiveLine.adapter

import android.content.res.ColorStateListimport android.text.TextUtilsimport android.util.Logimport android.view.LayoutInflaterimport android.view.Viewimport android.view.ViewGroupimport androidx.core.content.ContextCompatimport androidx.recyclerview.widget.RecyclerViewimport com.bumptech.glide.Glideimport com.google.firebase.firestore.FirebaseFirestoreimport com.google.firebase.firestore.ListenerRegistrationimport com.google.firebase.storage.FirebaseStorageimport com.wedoapps.cricketLiveLine.Rimport com.wedoapps.cricketLiveLine.databinding.LayoutHomeItemBindingimport com.wedoapps.cricketLiveLine.model.HomeMatchimport com.wedoapps.cricketLiveLine.model.Scoreimport com.wedoapps.cricketLiveLine.utils.Constantsimport com.wedoapps.cricketLiveLine.utils.Constants.TAGimport com.wedoapps.cricketLiveLine.utils.ShowLogToastimport java.text.SimpleDateFormatimport java.util.Calendarimport java.util.Locale

class HomeCardAdapter(private val listener: SetOnClick,private val homeMatchArrayList: ArrayList<HomeMatch>) : RecyclerView.Adapter<HomeCardAdapter.HomeCardViewHolder>() {

private var binderCounter = 0
private var createCounter = 0
val storageRef = FirebaseStorage.getInstance().reference
var fireStore = FirebaseFirestore.getInstance()
private var  fireStoreRef = fireStore.collection(Constants.collectionPathMatchList)

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeCardViewHolder {

    ShowLogToast.showLog("Counter for OnCreateViewHolder-->", createCounter.toString())
    createCounter++


    val binding =
        LayoutHomeItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
    return HomeCardViewHolder(binding)
}

override fun onBindViewHolder(holder: HomeCardViewHolder, position: Int) {

    val currentItem = homeMatchArrayList[position]

    ShowLogToast.showLog("Counter for onBindViewHolder-->", binderCounter.toString())
    binderCounter++


    with(holder) {

        binding.tvMatch.text = currentItem.matchDetail?.trim()

        if (currentItem.matchDate == null) {
            binding.tvTime.text = currentItem.currentDate?.trim()
        } else {
            fun Long?.getDateMatchList(): String {
                val sdf = SimpleDateFormat("dd MMMM yyyy, h:mm a", Locale.ENGLISH)
                val cal = Calendar.getInstance(Locale.ENGLISH)
                cal.timeInMillis = this?.times(1000L) ?: 0L
                return sdf.format(cal.time)
            }
            binding.tvTime.text = currentItem.matchDate.getDateMatchList()
        }




        when (currentItem.matchStatus) {
            Constants.statusUpcoming -> {
                Log.d(TAG, "UP: $currentItem")
                binding.tvOver.visibility = View.GONE
                binding.tvFInn.visibility = View.GONE
                binding.tvSecondFInn.visibility = View.GONE
                binding.tvSecondOver.visibility = View.GONE
                binding.tvFirstTeam.visibility = View.VISIBLE
                binding.tvSecondTeam.visibility = View.VISIBLE
                binding.tvRate1.visibility = View.VISIBLE
                binding.tvRate2.visibility = View.VISIBLE
                binding.tvFavTeam.visibility = View.VISIBLE
                binding.tvDayStatus.visibility = View.VISIBLE
                binding.relativeBottom.visibility = View.VISIBLE
                binding.btmDiv.visibility = View.VISIBLE
                binding.tvDayStatus.text = currentItem.venue?.trim()
                binding.tvMatchStatus.text = Constants.statusUpcoming
                binding.tvMatchStatus.backgroundTintList =
                    ColorStateList.valueOf(itemView.context.getColor(R.color.yellow_orange))
                binding.tvFirstTeam.text =
                    if (currentItem.fullNameTeam1.isNullOrEmpty()) currentItem.team1?.trim() else currentItem.fullNameTeam1!!.trim()
                binding.tvSecondTeam.text =
                    if (currentItem.fullNameTeam2.isNullOrEmpty()) currentItem.team2?.trim() else currentItem.fullNameTeam2!!.trim()
                binding.tvFirstTeam.maxLines = 3
                binding.tvSecondTeam.maxLines = 3
                binding.tvFirstTeam.setLineSpacing(0.8f, 0.8f)
                binding.tvSecondTeam.setLineSpacing(0.8f, 0.8f)
            }

            Constants.statusCompleted -> {
                binding.tvFInn.maxLines = 1
                binding.tvSecondFInn.maxLines = 1
                binding.tvFInn.visibility = View.VISIBLE
                binding.tvOver.visibility = View.VISIBLE
                binding.tvSecondFInn.visibility = View.VISIBLE
                binding.tvSecondOver.visibility = View.VISIBLE
                binding.tvFirstTeam.visibility = View.VISIBLE
                binding.tvSecondTeam.visibility = View.VISIBLE
                binding.tvRate1.visibility = View.GONE
                binding.tvRate2.visibility = View.GONE
                binding.tvFavTeam.visibility = View.GONE
                binding.btmDiv.visibility = View.INVISIBLE
                binding.tvDayStatus.visibility = View.GONE

                binding.tvMatchStatus.text = buildString {
                    append("Finished")
                }
                binding.relativeBottom.visibility = View.GONE

                binding.tvMatchStatus.backgroundTintList =
                    ColorStateList.valueOf(itemView.context.getColor(R.color.green))
                binding.tvFirstTeam.text =
                    if (currentItem.codeTeam1.isNullOrEmpty()) currentItem.team1?.trim() else currentItem.codeTeam1!!.trim()
                binding.tvSecondTeam.text =
                    if (currentItem.codeTeam2.isNullOrEmpty()) currentItem.team2?.trim() else currentItem.codeTeam2!!.trim()
            }

            Constants.statusLive -> {
                binding.tvFInn.maxLines = 1
                binding.tvSecondFInn.maxLines = 1
                binding.tvFInn.visibility = View.VISIBLE
                binding.tvOver.visibility = View.VISIBLE
                binding.tvSecondFInn.visibility = View.VISIBLE
                binding.tvSecondOver.visibility = View.VISIBLE
                binding.tvFirstTeam.visibility = View.VISIBLE
                binding.tvSecondTeam.visibility = View.VISIBLE
                binding.tvRate1.visibility = View.VISIBLE
                binding.tvRate2.visibility = View.VISIBLE
                binding.tvFavTeam.visibility = View.VISIBLE
                binding.tvDayStatus.visibility = View.VISIBLE
                binding.relativeBottom.visibility = View.VISIBLE
                binding.btmDiv.visibility = View.VISIBLE
                binding.tvMatchStatus.text = buildString {
                    append("◉ LIVE")
                }
                binding.tvMatchStatus.backgroundTintList =
                    ColorStateList.valueOf(itemView.context.getColor(R.color.colorRed))
                binding.tvFirstTeam.text =
                    if (currentItem.codeTeam1.isNullOrEmpty()) currentItem.team1?.trim() else currentItem.codeTeam1!!.trim()
                binding.tvSecondTeam.text =
                    if (currentItem.codeTeam2.isNullOrEmpty()) currentItem.team2?.trim() else currentItem.codeTeam2!!.trim()
            }

            else -> {
                binding.tvMatchStatus.text = currentItem.matchStatus?.trim()
            }

        }


        val imgPlayerDrawableDefault =
            ContextCompat.getDrawable(itemView.context, R.drawable.imgpsh_fullsize_anim)

        val fileReference1 =
            storageRef.child(Constants.flagIconPath + currentItem.team1?.trim { it <= ' ' } + ".png")


        fileReference1.metadata.addOnSuccessListener {

            if (it.name != null && it.sizeBytes > 0) {
                fileReference1.downloadUrl.addOnSuccessListener { uri ->
                    Log.d(TAG, "TeamH1URL: $uri")
                    Glide.with(itemView.context)
                        .load(uri)
                        .centerCrop()
                        .placeholder(R.drawable.imgpsh_fullsize_anim)
                        .into(binding.ivFirstTeam)
                }.addOnFailureListener {
                    binding.ivFirstTeam.setImageDrawable(
                        imgPlayerDrawableDefault
                    )
                }
            }

        }.addOnFailureListener {
            ShowLogToast.showLog("Storage Exception Team1 flag-->", it.localizedMessage)

        }


        val fileReference2 =
            storageRef.child(Constants.flagIconPath + currentItem.team2?.trim { it <= ' ' } + ".png")

        fileReference2.metadata.addOnSuccessListener {

            if (it.name != null && it.sizeBytes > 0) {
                fileReference2.downloadUrl.addOnSuccessListener { uri ->
                    Log.d(TAG, "TeamH2URL: $uri")
                    Glide.with(itemView.context)
                        .load(uri)
                        .centerCrop()
                        .placeholder(R.drawable.imgpsh_fullsize_anim)
                        .into(binding.ivSecondTeam)
                }.addOnFailureListener {
                    binding.ivSecondTeam.setImageDrawable(
                        imgPlayerDrawableDefault
                    )
                }


            }

        }.addOnFailureListener {
            ShowLogToast.showLog("Storage Exception Team2 flag-->", it.localizedMessage)
        }


       fireStoreRef.document(currentItem.id!!).collection(Constants.lastBallInfoKey)
            .document(Constants.lbdKey)
            .addSnapshotListener { value, error ->
                if (error != null) {
                    Log.w(TAG, "Listen Failed", error)
                    return@addSnapshotListener
                }

                if (value != null) {
                    val data = value.data
                    if (data != null) {
                        val ballByBall: String = data[Constants.ballByBallKey] as String
                        Log.d(TAG, "LBD: $data")

                        binding.txtBallByBallUpdate.text = ballByBall

                        when {

                            ballByBall.contentEquals("0 Run") -> {
                                binding.txtBallByBallUpdate.text = "0"
                            }

                            ballByBall.contentEquals("1 Run") -> {
                                binding.txtBallByBallUpdate.text = "1"
                            }

                            ballByBall.contentEquals("2 Run") -> {
                                binding.txtBallByBallUpdate.text = "2"
                            }

                            ballByBall.contentEquals("3 Run") -> {
                                binding.txtBallByBallUpdate.text = "3"
                            }

                            ballByBall.contentEquals("It's 6") -> {
                                binding.txtBallByBallUpdate.text = "6-6-6"
                            }

                            ballByBall.contentEquals("It's 4") -> {
                                binding.txtBallByBallUpdate.text = "4-4-4"
                            }

                            ballByBall.contentEquals("WD + 1") -> {
                                binding.txtBallByBallUpdate.text = buildString {
                                    append("WD1")
                                }
                            }

                            ballByBall.contentEquals("WD + 2") -> {
                                binding.txtBallByBallUpdate.text = buildString {
                                    append("WD2")
                                }
                            }

                        }


                    }
                } else {
                    Log.d(TAG, "No Data")
                }
            }

        fireStoreRef.document(currentItem.id!!).collection(Constants.matchRateKey)
            .document(Constants.matchKey)
            .addSnapshotListener { value, error ->
                if (error != null) {
                    Log.w(TAG, "Listen Failed", error)
                    return@addSnapshotListener
                }

                if (value != null) {
                    val data = value.data
                    if (data != null) {

                        val it = data.toString()
                        val value1 = it.substring(1, it.length - 1)
                        val keyValuePair = value1.split(",")
                        val map = hashMapOf<String, String>()

                        keyValuePair.forEach { text ->
                            val entry = text.split("=")
                            map[entry[0].trim()] = entry[1].trim()
                        }

                        val favTeam = map[Constants.favTeamKey]?.trim()
                        val rate1 = map[Constants.rate1Key]?.trim()
                        val rate2 = map[Constants.rate2Key]?.trim()



                        when (currentItem.matchStatus) {
                            Constants.statusUpcoming -> {
                                if (TextUtils.isEmpty(favTeam)) {
                                    binding.tvFavTeam.visibility = View.GONE
                                } else {
                                    binding.tvFavTeam.visibility = View.VISIBLE
                                    binding.tvFavTeam.text = favTeam
                                }

                                if (TextUtils.isEmpty(rate1)) {
                                    binding.tvRate1.visibility = View.GONE
                                } else {
                                    binding.tvRate1.visibility = View.VISIBLE
                                    binding.tvRate1.text = rate1
                                }

                                if (TextUtils.isEmpty(rate2)) {
                                    binding.tvRate2.visibility = View.GONE
                                } else {
                                    binding.tvRate2.visibility = View.VISIBLE
                                    binding.tvRate2.text = rate2
                                }

                            }

                            Constants.statusLive -> {
                                if (TextUtils.isEmpty(favTeam)) {
                                    binding.tvFavTeam.visibility = View.GONE
                                } else {
                                    binding.tvFavTeam.visibility = View.VISIBLE
                                    binding.tvFavTeam.text = favTeam
                                }

                                if (TextUtils.isEmpty(rate1)) {
                                    binding.tvRate1.visibility = View.GONE
                                } else {
                                    binding.tvRate1.visibility = View.VISIBLE
                                    binding.tvRate1.text = rate1
                                }

                                if (TextUtils.isEmpty(rate2)) {
                                    binding.tvRate2.visibility = View.GONE
                                } else {
                                    binding.tvRate2.visibility = View.VISIBLE
                                    binding.tvRate2.text = rate2
                                }

                            }

                            Constants.statusCompleted -> {
                                binding.tvFavTeam.visibility = View.GONE
                                binding.tvRate1.visibility = View.GONE
                                binding.tvRate2.visibility = View.GONE

                            }

                        }




                        Log.d(TAG, "mr: $data")
                    } else {

                        binding.tvFavTeam.visibility = View.GONE
                        binding.tvRate2.visibility = View.GONE
                        binding.tvRate1.visibility = View.GONE

                    }

                } else {
                    Log.d(TAG, "No Data")

                    binding.tvFavTeam.visibility = View.GONE
                    binding.tvRate2.visibility = View.GONE
                    binding.tvRate1.visibility = View.GONE


                }
            }




        fireStoreRef.document(currentItem.id!!).collection(Constants.collectionPathLiveMatch)
            .document(Constants.runRateInfoKey)
            .addSnapshotListener { value, error ->
                if (error != null) {
                    Log.w(TAG, "Listen Failed", error)
                    return@addSnapshotListener
                }

                if (value != null) {
                    val data = value.data
                    if (data != null) {
                        val it = data.toString()
                        val value1 = it.substring(1, it.length - 1)
                        val keyValuePair = value1.split(",")
                        val map = hashMapOf<String, String>()

                        keyValuePair.forEach { text ->
                            val entry = text.split("=")
                            map[entry[0].trim()] = entry[1].trim()
                        }

                        binding.tvDayStatus.text = if (map[Constants.otherInfoKey]?.trim()
                                .isNullOrEmpty() || map[Constants.otherInfoKey].equals("") || map[Constants.otherInfoKey].equals(
                                "-"
                            )
                        ) if (currentItem.venue.isNullOrEmpty()) "" else "${currentItem.venue}" else map[Constants.otherInfoKey]?.trim()
                        Log.d(TAG, "getRunRate: $data")



                    }

                } else {
                    Log.d(TAG, "No Data")
                }
            }


        fireStoreRef.document(currentItem.id!!.toString())
            .collection(Constants.collectionPathLiveMatch).document(Constants.scoreTeam1Key)
            .addSnapshotListener { value, error ->
                if (error != null) {
                    Log.w(TAG, "Listen Failed", error)
                    return@addSnapshotListener
                }

                if (value != null) {
                    val allTeam1 = value.toObject(Score::class.java)
                    binding.tvFInn.text = value.get(Constants.scoreKey).toString().trim()
                    binding.tvOver.text = buildString {
                        append("( ")
                        append(value.get(Constants.overKey).toString())
                        append(" )")
                    }

                    //val allTeam1 = ArrayList<Score>()
                    //allTeam1?.add(allTeam1)

                    Log.d(TAG, "team1 HomeCard: $allTeam1")
                } else {
                    Log.d(TAG, "No Data")
                }


            }




        fireStoreRef.document(currentItem.id!!.toString())
            .collection(Constants.collectionPathLiveMatch).document(Constants.scoreTeam2Key)
            .addSnapshotListener { value, error ->
                if (error != null) {
                    Log.w(TAG, "Listen Failed", error)
                    return@addSnapshotListener
                }

                if (value != null) {
                    val allTeam2 = value.toObject(Score::class.java)
                    binding.tvSecondFInn.text = value.get(Constants.scoreKey).toString().trim()
                    binding.tvSecondOver.text = buildString {
                        append("( ")
                        append(value.get(Constants.overKey).toString())
                        append(" )")
                    }


                    Log.d(TAG, "team2: $allTeam2")
                } else {
                    Log.d(TAG, "No Data")
                }
            }





    }


}


override fun getItemCount(): Int {

    ShowLogToast.showLog("HomeCardAdapter size-->", homeMatchArrayList.size.toString())
    return homeMatchArrayList.size
    // return differ.currentList.size
}

override fun onViewRecycled(holder: HomeCardViewHolder) {
    super.onViewRecycled(holder)
    val position: Int = holder.absoluteAdapterPosition

}
inner class HomeCardViewHolder(var binding: LayoutHomeItemBinding) :
    RecyclerView.ViewHolder(binding.root) {
    init {
        binding.root.setOnClickListener {
            val position = absoluteAdapterPosition
            if (position != RecyclerView.NO_POSITION) {
                val item = homeMatchArrayList[position]
                listener.onClick(item)
            }
        }
    }


}


/*  private val differCallback = object : DiffUtil.ItemCallback<HomeMatch>() {
      override fun areItemsTheSame(oldItem: HomeMatch, newItem: HomeMatch) =
          oldItem.id == newItem.id

      override fun areContentsTheSame(oldItem: HomeMatch, newItem: HomeMatch) =
          oldItem.id == newItem.id
  }

  val differ = AsyncListDiffer(this, differCallback)*/

interface SetOnClick {
    fun onClick(match: HomeMatch)
}

}

`

这是我的片段调用和列表的重新引用。我确认问题出在适配器类而不是片段类上。调试并打印日志检查三次。

` 类 HomeMatchListFragment : BaseFragment(), View.OnClickListener, HomeCardAdapter.SetOnClick { private val tagHomeMatch: String = "HomeMatchListFragment" private Lateinit var mBinding:FragmentHomeMatchListBinding

private var mContext: Context? = null
private var dialog: Dialog? = null
private lateinit var viewModel: CricketGuruViewModel

private val fireStore = FirebaseFirestore.getInstance()
private val firestorage = FirebaseStorage.getInstance()
private val storageRef = firestorage.reference

private var permissionChecker: PermissionChecker? = null

private lateinit var matchScoreListAdapter: HomeCardAdapter

private var team1 = ArrayList<String>()
private var team2 = ArrayList<String>()
private var homeMatchArrayList: ArrayList<HomeMatch> = ArrayList()

override fun onAttach(context: Context) {
    super.onAttach(context)
    mContext = context
    permissionChecker = PermissionChecker(mContext!!)

}

override fun getInflateResource(): Int {
    return R.layout.fragment_home_match_list
}

override fun displayMessage(message: String) {
    mBinding.root.snack(message)
}

override fun initView() {
    mBinding = getBinding()
    viewModel = (activity as MainActivity).viewModel
    setRecyclerView()


}

override fun postInit() {

}

override fun handleListener() {
}

override fun initProgressBar() {
    dialog = Dialog(requireContext())
    dialog!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
    dialog!!.setContentView(R.layout.dialog_progress)
    dialog!!.setCancelable(false)
}

override fun showLoadingIndicator(isShow: Boolean) {
    dialog!!.isVisible(isShow, dialog)
}


private fun setRecyclerView() {

    matchScoreListAdapter = HomeCardAdapter(this,homeMatchArrayList)

    val mLayoutManager: RecyclerView.LayoutManager = LinearLayoutManager(context)
    mBinding.recyclerViewHomeLiveMatchList.layoutManager = mLayoutManager
    mBinding.recyclerViewHomeLiveMatchList.itemAnimator = DefaultItemAnimator()
    mBinding.recyclerViewHomeLiveMatchList.setHasFixedSize(true)
    mBinding.recyclerViewHomeLiveMatchList.adapter = matchScoreListAdapter


    // Set the RecyclerViewPool to the RecyclerViews
    mBinding.recyclerViewHomeLiveMatchList.recycledViewPool.clear()

    showShimmerViewVisibility(true)

    var count =0
    viewModel.getAllMatch().observe(this) {
       // matchScoreListAdapter.differ.submitList(it?.toMutableList())

        count++
        ShowLogToast.showLog(tagHomeMatch, "Count is-->$count")
        homeMatchArrayList.clear()
        homeMatchArrayList.addAll(it)

        if (it.size > 0) {
           // matchScoreListAdapter.notifyItemRangeInserted(0,homeMatchArrayList.size)
            setRecyclerViewVisibility(true)
        } else {
            setRecyclerViewVisibility(false)
        }

        showShimmerViewVisibility(false)

        ShowLogToast.showLog("Test Home Array Size", it.size.toString())
    }

    if(homeMatchArrayList.size >0){
         matchScoreListAdapter.notifyItemRangeInserted(0,homeMatchArrayList.size)
    }



}


private fun showShimmerViewVisibility(b: Boolean) {
    if (b) {
        mBinding.recyclerViewHomeLiveMatchList.showShimmerAdapter()
    } else {
        mBinding.recyclerViewHomeLiveMatchList.hideShimmerAdapter()

    }
}
private fun setRecyclerViewVisibility(b: Boolean) {
    if (b) {
        mBinding.txtNoDataHomeLiveMatchList.visibility = View.GONE
        mBinding.recyclerViewHomeLiveMatchList.visibility = View.VISIBLE
    } else {
        mBinding.recyclerViewHomeLiveMatchList.visibility = View.GONE
        mBinding.txtNoDataHomeLiveMatchList.visibility = View.VISIBLE
    }
}


override fun onClick(v: View?) {
    when (v!!.id) {
        /* R.id.linearHomeAdsLiveMatch->{
             CommonUtils.gotoAdsContact(mContext!!)

         }*/
    }

}

override fun onClick(match: HomeMatch) {
    val intentHomeFragment = Intent(requireActivity(), ViewPagerActivity::class.java)
    intentHomeFragment.putExtra("match", match)
    startActivity(intentHomeFragment)
}


override fun onResume() {
    super.onResume()
    if (homeMatchArrayList.size > 0) {
        matchScoreListAdapter.notifyItemRangeChanged(0, homeMatchArrayList.size)
    }

}

}

这是 Reyclerview 的适配器类 我的问题是,当我在 onBindViewHolder 方法中调用 firebase 文档时,由于 addSnapshotListener 的回调,它会调用无限循环,因为当 firebase 添加快照 Litener 并设置为特定文本视图时,我需要立即反映数据。我已经在我的旧项目上工作正常,但现在它不起作用。

kotlin google-cloud-firestore android-recyclerview android-adapter
1个回答
0
投票

首先将侦听器移出 viewHolders,切勿在 Adapters/ViewHolders 中设置 firebase 侦听器或任何类型的服务, ViewHolders/Adapters 应该只负责创建和绑定视图,它们不能知道数据来自何处的数据服务。 试试这个它会解决所有问题

© www.soinside.com 2019 - 2024. All rights reserved.