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

Firestore获取集合内ArrayList全量数据失败 RecyclerView仅显示最后项

问题根因

该问题与Firestore数据读取逻辑无关,是RecyclerView适配器数据类型定义错误+列表数据层级嵌套错误共同导致的:

  • 适配器泛型定义错误:每个RecyclerView条目应当对应单条HolderHistItem数据,当前代码将ArrayList<HolderHistItem>作为单个列表项的数据类型,等于把整组历史记录塞给了一个item布局。
  • item绑定逻辑错误:setData方法中遍历整个历史数组反复给同一个TextView赋值,前面的赋值会被后续遍历覆盖,最终只会留下数组最后一个元素的内容。
  • 数据拉取层返回结构错误:查询id匹配的Holder文档后,将每个文档自带的holderHistoryItem数组又包装成了外层列表,返回值成了嵌套的List<ArrayList<HolderHistItem>>,和适配器的错误类型匹配后,最终只会渲染1个item、显示最后一条数据。
修复方案

1. 修正数据获取函数的返回结构

查询指定id的Holder文档时,匹配结果理论上只有1条文档,不需要把文档数组再map成嵌套列表,直接取出对应文档里的holderHistoryItem字段作为返回列表即可:

@ExperimentalCoroutinesApi
fun getAllInstrumentInHolderHistory(holder: Holder): Flow<State<List<HolderHistItem>>> =
    callbackFlow {
        val snapshotListener = holderCollection
            .orderBy("name")
            .whereEqualTo("id",holder.id)
            .addSnapshotListener { value , error ->
                val response = if (error == null && value != null) {
                    trySend(State.loading())
                    // 匹配指定id的Holder只会有1个文档,直接取第一条,拿出内部的历史列表
                    val data = value.documents.mapNotNull { doc ->
                        doc.toObject(Holder::class.java)
                    }.firstOrNull()?.holderHistoryItem ?: emptyList()
                    State.success(data)
                } else {
                    State.failed(error.toString())
                }
                trySend(response)
            }
        awaitClose {
            snapshotListener.remove()
        }
    }

注意:对应ViewModel中持有该Flow的变量类型也要同步修改为State<List<HolderHistItem>>,保持类型一致。

2. 修正RecyclerView适配器的泛型与绑定逻辑

将适配器的单条数据类型改为HolderHistItem,去掉遍历逻辑,直接绑定单条数据到控件:

// 泛型改为单条HolderHistItem
class HolderHistAdapter : ListAdapter<HolderHistItem,HolderHistAdapter.ItemHist>(ItemComparator()) {
    class ItemHist(view: View) : RecyclerView.ViewHolder(view) {

        private val b = HistitemItemBinding.bind(view)

        @SuppressLint("SetTextI18n")
        // 入参改为单条HolderHistItem,去掉遍历
        fun setData(holderHistItem: HolderHistItem) = with(b){
            tvListName.text = holderHistItem.instrName.toString()
            tvGet.text = holderHistItem.getTime.toString()
            tvReturn.text = holderHistItem.returnTime.toString()
        }
        companion object {
            fun create(parent: ViewGroup): HolderHistAdapter.ItemHist {
                return HolderHistAdapter.ItemHist(
                    LayoutInflater.from(parent.context)
                        .inflate(R.layout.histitem_item, parent, false)
                )
            }
        }
    }

    class ItemComparator : DiffUtil.ItemCallback<HolderHistItem>() {
        override fun areItemsTheSame(oldItem: HolderHistItem, newItem: HolderHistItem): Boolean {
            // 用业务id判断是否是同一条,不要用hashCode
            return oldItem.id == newItem.id
        }

        override fun areContentsTheSame(oldItem: HolderHistItem, newItem:HolderHistItem): Boolean {
            return oldItem == newItem
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemHist {
        return ItemHist.create(parent)
    }

    override fun onBindViewHolder(holder: ItemHist, position: Int) {
        holder.setData(getItem(position))
    }
}

3. 修正页面观察数据的逻辑

适配修改后的返回值类型,直接提交拉取到的历史列表即可:

fun observHistoryItem(){
    mainViewModel.getAllInstrHistoryItem(holder!!).observe(viewLifecycleOwner,{
        when (it) {
            is State.Loading -> {
                // 可按需实现loading状态展示
            }
            is State.Success -> {
                if(it.data.isEmpty()){
                    b.rcHistItem.visibility = View.GONE
                    b.tvEmptyHist.visibility = View.VISIBLE
                }else {
                    // 直接提交单条历史项组成的列表
                    adapterHis.submitList(it.data)
                    b.rcHistItem.visibility = View.VISIBLE
                }
            }
            is State.Failed -> {
                Log.d("Error" , "Error name :${it.message}")
            }
        }
    })
}

额外提示:DiffUtil判断元素是否相同时不要用hashCode比对,用数据模型里唯一的业务id判断,避免列表刷新时出现条目错乱、不更新的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 05:15:55