首页 > 解决方案 > LiveData 观察者调用了两次

问题描述

我有一个名为的片段loanFragment,它根据付款次数计算并显示应付贷款的剩余金额。它有一个名为 viewmodel LoanViewModel,其中包含remainingAmountloanPaymentslivedata。loanFragment我在for the中设置了观察者,remainingAmount这样loanPayments每当这些数据发生变化时,就会触发剩余金额的计算,并相应loanFragment地更新 UI。

问题是如果我导航到另一个片段然后导航回loanFragment,观察者loanPayments被调用两次,这也导致计算剩余量两次。另一方面,观察者remainingAmount工作正常。该问题仅发生在 loanPayments. 仅在loanPayments从后端获取付款后才修改实时数据。但是在导航回 之后,即使尚未触发支付的获取,也会调用loanFragment观察者。loanPayments然后在提取贷款付款完成后再次调用它。loanFragment请注意,第一次打开时不会出现问题。我不确定我错过了什么或我的代码中的错误在哪里。

LoanFragment代码:

class LoanFragment : Fragment() {
    private val loanViewModel: LoanViewModel by activityViewModels()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_loan, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        // Init data
        loanViewModel.remainingAmount.observe(viewLifecycleOwner, { remainingAmount ->
            setUpRemainingAmount(view, remainingAmount)
        })

        loanViewModel.loanPayments.observe(viewLifecycleOwner, { payments ->
             loanViewModel.remainingAmount.value?.let {
                 var remainingAmount = it
                 payments.forEach { payment -> remainingAmount -= payment.amount }
                 loanViewModel.remainingAmount.value = remainingAmount
            }
        })

        loanViewModel.selectedLoan.value?.let { loan ->
            loanViewModel.remainingAmount.value = loan.amount
            loanViewModel.fetchLoanPayments(loan.uid)
        }
    }

    private fun setUpRemainingAmount(view: View, remainingAmount: Double) {
        val tvRemainingAmount: TextView = view.findViewById(R.id.tvRemainingAmount)
        val formatter = DecimalFormat("#,###.00")
        val amount = "₱" + formatter.format(loanViewModel.remainingAmount.value)
        tvRemainingAmount.text = amount
    }
}

LoanViewModel代码:

@HiltViewModel
class LoanViewModel @Inject constructor(
    private val paymentRepository: PaymentRepository,
) : ViewModel() {
    val loanPayments = MutableLiveData<MutableList<Payment>>()
    val selectedLoan = MutableLiveData<Loan>()
    var remainingAmount = MutableLiveData<Double>()

    fun fetchLoanPayments(uid: String) {
        val task = paymentRepository.fetchLoanPayments(uid)
        task.addOnSuccessListener { result ->
            val payments = mutableListOf<Payment>()

            for (document in result)
                Payment(document.data as HashMap<*, *>).let(payments::add)

            loanPayments.value = payments
        }.addOnFailureListener { e ->
            Utils.print("Error getting documents: " + e.message)
        }
    }
}

我还在LoanPaymentsFragment. 它是 的子片段LoanFragment。它的责任是只显示付款。我不确定它是否相关,但我想也包括它的代码。

class LoanPaymentsFragment : Fragment() {
    private lateinit var paymentsRvAdapter: PaymentsRvAdapter
    private val paymentsList = mutableListOf<Payment>()
    private val loanViewModel: LoanViewModel by activityViewModels()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_loan_payments, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        // Payments list listener
        loanViewModel.loanPayments.observe(viewLifecycleOwner, {
            paymentsList.clear()
            paymentsList.addAll(it)
            paymentsRvAdapter.notifyDataSetChanged()
        })

        setUpRecyclerView(view)
    }
}

标签: androidandroid-livedata

解决方案


推荐阅读