You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将RecyclerView Adapter计算的账户余额传递至Fragment并自动更新(Kotlin)

解决方案

你原有代码中存在逻辑错误:onBindViewHolder是单个条目绑定时触发的方法,其中定义的totalIncome和totalexpense是单次调用的局部变量,最终得到的MainAccountBalance仅为当前条目的收支差,并非所有条目的总余额。

我们可以通过接口回调的方式实现余额实时同步到Fragment,完整实现如下:


步骤1:修改RecyclerViewAdapter代码

新增余额更新回调接口,在Firestore数据变更的系统回调中遍历所有条目计算总余额,再通过回调抛出结果:

class RecyclerViewAdapter(options: FirestoreRecyclerOptions<DataModel>) : FirestoreRecyclerAdapter<DataModel,  RecyclerViewAdapter.MyViewHolder>(options) {
    private var listener: OnItemClickListener? = null
    // 新增:余额更新回调接口
    interface OnBalanceUpdateListener {
        fun onBalanceUpdated(balance: Double)
    }
    private var balanceListener: OnBalanceUpdateListener? = null

    // 新增:设置余额更新监听器的方法
    fun setOnBalanceUpdateListener(listener: OnBalanceUpdateListener?) {
        this.balanceListener = listener
    }

    // 重写:Firestore数据变更时自动触发的回调
    override fun onDataChanged() {
        super.onDataChanged()
        var totalIncome = 0.0
        var totalExpense = 0.0
        // 遍历所有条目计算总收支
        for (item in snapshots) {
            if (item.transaction_type == "expense") {
                totalExpense += item.transaction_amount ?: 0.0
            } else {
                totalIncome += item.transaction_amount ?: 0.0
            }
        }
        val mainAccountBalance = totalIncome - totalExpense
        // 将计算完成的余额通过回调抛出
        balanceListener?.onBalanceUpdated(mainAccountBalance)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int, model: DataModel) {
        holder.noteTextView.setText(model.transaction_note)
        holder.transactionDateTextView.setText(model.transaction_timestamp?.let { convertLongToDateString(it) }).toString()

        // 删去原这里的总收支计算逻辑,仅保留单条目展示逻辑
        val transaction_type = model.transaction_type
        if (transaction_type=="expense") {
            holder.amountTextView.setTextColor(Color.parseColor("#D12E9A"))
            holder.amountTextView.text = model.transaction_amount?.let { replaceArabicNumbers(convertIntToCurrencyString(it)) }
        } else {
            holder.amountTextView.setTextColor(Color.parseColor("#3A86FF"))
            holder.amountTextView.text = model.transaction_amount?.let { replaceArabicNumbers(convertIntToCurrencyString(it)) }
        }
    }

    // 以下原有代码保持不变
    public fun replaceArabicNumbers(original: kotlin.String): kotlin.String {
        return original
            .replace("٠","0")
            .replace("١","1")
            .replace("٢","2")
            .replace("٣","3")
            .replace("٤","4")
            .replace("٥","5")
            .replace("٦","6")
            .replace("٧","7")
            .replace("٨","8")
            .replace("٩","9")
            .replace("٫",".")
            .replace("٬",",")
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val v: View = LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_main_account_item,
            parent, false)
        return MyViewHolder(v)
    }

    fun deleteItem(position: Int) {
        snapshots.getSnapshot(position).reference.delete()
    }

    inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var transactionDateTextView: TextView
        var noteTextView: TextView
        var amountTextView: TextView

        init {
            transactionDateTextView = itemView.findViewById(R.id.transactionDateTextView)
            noteTextView = itemView.findViewById(R.id.noteTextView)
            amountTextView = itemView.findViewById(R.id.amountTextView)

            itemView.setOnClickListener {
                val position = adapterPosition
                if (position != RecyclerView.NO_POSITION && listener != null) {
                    listener!!.onItemClick(snapshots.getSnapshot(position), position)
                }
            }
        }
    }

    interface OnItemClickListener {
        fun onItemClick(documentSnapshot: DocumentSnapshot?, position: Int)
    }

    fun setOnItemClickListener(listener: OnItemClickListener?) {
        this.listener = listener
    }

    fun convertLongToDateString(systemTime: Long): kotlin.String {
        return SimpleDateFormat("dd-MM-yyyy")
            .format(systemTime).toString()
    }

    fun convertIntToCurrencyString(money :Double): kotlin.String {
        val formatter: NumberFormat = DecimalFormat("#,###.##")
        return formatter.format(money)
    }
}

onDataChanged方法会在首次加载数据、条目增删改、列表刷新时自动触发,完全满足你要求的自动更新场景。


步骤2:在MainFragment中接收余额更新

实现余额回调接口,拿到结果后更新顶部TextView即可:

class MainFragment : Fragment() {
    private lateinit var adapter: RecyclerViewAdapter
    // 你布局中RecyclerView顶部展示余额的TextView
    private lateinit var balanceTextView: TextView
    private lateinit var yourRecyclerView: RecyclerView

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 初始化控件
        balanceTextView = view.findViewById(R.id.your_balance_textview_id)
        yourRecyclerView = view.findViewById(R.id.your_recyclerview_id)
        yourRecyclerView.layoutManager = LinearLayoutManager(context)

        // 原有Firestore查询逻辑保持不变
        val yourQuery = FirebaseFirestore.getInstance().collection("your_transaction_collection")
        val options = FirestoreRecyclerOptions.Builder<DataModel>()
            .setQuery(yourQuery, DataModel::class.java)
            .build()

        // 初始化Adapter
        adapter = RecyclerViewAdapter(options)

        // 设置余额更新监听
        adapter.setOnBalanceUpdateListener(object : RecyclerViewAdapter.OnBalanceUpdateListener {
            override fun onBalanceUpdated(balance: Double) {
                // 格式化后更新TextView
                val formatted = adapter.replaceArabicNumbers(adapter.convertIntToCurrencyString(balance))
                balanceTextView.text = "账户余额:$formatted"
            }
        })

        // 原有条目点击逻辑保持不变
        adapter.setOnItemClickListener(object : RecyclerViewAdapter.OnItemClickListener {
            override fun onItemClick(documentSnapshot: DocumentSnapshot?, position: Int) {
                // 你原有的点击处理逻辑
            }
        })

        yourRecyclerView.adapter = adapter
        // 开启Firestore数据监听
        adapter.startListening()
    }

    override fun onDestroyView() {
        super.onDestroyView()
        // 停止Firestore数据监听
        adapter.stopListening()
    }
}

内容的提问来源于stack exchange,提问作者Rashid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 18:45:03