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

Android:从Firebase获取的数据无法添加至myPetsList列表

问题描述

我在Kotlin中开发了一个Fragment,尝试从Firebase获取数据。目前已成功获取到Firebase返回的数据(能打印出宠物名称),但无法将这些数据添加到myPetsList列表中并更新RecyclerView显示。以下是我的Fragment和Adapter代码:

Fragment代码

package com.example.touchpet

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.databinding.DataBindingUtil
import com.example.touchpet.databinding.FragmentMyPetsBinding
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import com.example.touchpet.MyPetsAdapter

private const val ARG_PARAM1 = "param1"

class MyPetsFragment : Fragment() {
    private var param1: String? = null
    private lateinit var binding: FragmentMyPetsBinding
    private lateinit var myPetsList: ArrayList<Pet>
    private lateinit var adapter: MyPetsAdapter
    private lateinit var firebaseAuth: FirebaseAuth
    private lateinit var db: FirebaseDatabase
    private lateinit var petRef: DatabaseReference
    private lateinit var cUser: User

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    // Inflate the layout for this fragment
    binding = DataBindingUtil.inflate(inflater,R.layout.fragment_my_pets,container,false)
    firebaseAuth = FirebaseAuth.getInstance()
    db = FirebaseDatabase.getInstance()
    petRef = db.getReference("pet")
    myPetsList= arrayListOf()
    adapter= MyPetsAdapter(requireContext(),myPetsList)
    binding.myPetsAdapter=adapter
    getPetsData()

    Log.d("DEBUG", "List size: ${myPetsList.size}")
    return binding.root
}

fun getPetsData() {
    val userId = firebaseAuth.currentUser?.uid
    if (userId == null) {
        Log.e("FirebaseAuth", "User is not logged in")
        return
    }

    petRef.addValueEventListener(object : ValueEventListener {
        override fun onDataChange(snapshot: DataSnapshot) {
            myPetsList.clear()
            if (snapshot.exists()) {
                for (petSnapshot in snapshot.children) {
                    val pet = petSnapshot.getValue(Pet::class.java)
                    Log.e("FirebasePet", "${pet?.pet_name.toString()}")
                    pet?.let { myPetsList.add(it) }
                }
                binding.myPetsAdapter?.updateItems(myPetsList)  // Notify the adapter

            } else {
                Log.d("FirebaseData", "No pets found")
            }
        }

        override fun onCancelled(error: DatabaseError) {
            Log.e("FirebaseError", "Database error: ${error.message}", error.toException())
            }
        })
}

companion object {
    @JvmStatic
    fun newInstance(param1:String) =
        MyPetsFragment().apply {
            arguments = Bundle().apply {
                putString(ARG_PARAM1, param1)
            }
        }
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    arguments?.let {
        param1 = it.getString(ARG_PARAM1)
    }
}
}

Adapter代码

package com.example.touchpet

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.touchpet.databinding.CardviewPetBinding

class MyPetsAdapter(private val mContext:Context, private var cardList: List<Pet?>)
    :RecyclerView.Adapter<MyPetsAdapter.CardTasarimNesneleriTutucu>(){
        private var listenerItems: onItemClickListener? = null
    inner class CardTasarimNesneleriTutucu(cardTasarimBinding: CardviewPetBinding, private val listener: onItemClickListener?): RecyclerView.ViewHolder(cardTasarimBinding.root),
        View.OnClickListener{
        var cardTasarimBinding: CardviewPetBinding

    init {
        this.cardTasarimBinding = cardTasarimBinding
    }

    override fun onClick(v: View?) {
        val position = adapterPosition
        if (position != RecyclerView.NO_POSITION) {
            listener?.onItemClick(position)
        }
    }

}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardTasarimNesneleriTutucu {
    val layoutInflater = LayoutInflater.from(mContext)
    val cardTasarimBinding = CardviewPetBinding.inflate(layoutInflater,parent,false)
    return CardTasarimNesneleriTutucu(cardTasarimBinding,listenerItems)
}

override fun getItemCount(): Int {
    return cardList.size
}

override fun onBindViewHolder(holder: MyPetsAdapter.CardTasarimNesneleriTutucu, position: Int) {
    val card = cardList.get(position)
    holder.cardTasarimBinding.myPetNesne = card

}

fun updateItems(newItems: List<Pet>) {
    this.cardList = newItems
    notifyDataSetChanged()
}

interface onItemClickListener {
    fun onItemClick(position: Int)
}

fun setOnItemClickListener(listener: onItemClickListener) {
    listenerItems = listener
}
}

问题分析与解决方案

核心问题点

  1. 异步回调时序误解:你在onCreateView中打印myPetsList.size时,Firebase的onDataChange回调还未执行(Firebase数据请求是异步的),此时列表确实为空,但数据后续会被正常添加,只是日志时机不对。
  2. 数据类型不兼容:Adapter构造函数接收List<Pet?>,但你传入的是ArrayList<Pet>,后续updateItems传入List<Pet>赋值给cardList时存在隐式类型转换,可能导致数据绑定异常。
  3. 布局绑定验证缺失:未确认RecyclerView在布局文件中是否正确绑定了adapter。

具体修复步骤

1. 修正日志打印位置

将列表大小的日志移到onDataChange回调内,确保打印的是数据加载后的真实状态:

override fun onDataChange(snapshot: DataSnapshot) {
    myPetsList.clear()
    if (snapshot.exists()) {
        for (petSnapshot in snapshot.children) {
            val pet = petSnapshot.getValue(Pet::class.java)
            Log.e("FirebasePet", "${pet?.pet_name.toString()}")
            pet?.let { myPetsList.add(it) }
        }
        binding.myPetsAdapter?.updateItems(myPetsList)
        Log.d("DEBUG", "List size after fetch: ${myPetsList.size}") // 移至此处
    } else {
        Log.d("FirebaseData", "No pets found")
        Log.d("DEBUG", "List size: ${myPetsList.size}")
    }
}

2. 统一数据类型

将Adapter的构造函数参数改为List<Pet>,避免可空类型混淆:

class MyPetsAdapter(private val mContext: Context, private var cardList: List<Pet>)
    : RecyclerView.Adapter<MyPetsAdapter.CardTasarimNesneleriTutucu>() {
    // ... 其余代码不变
    override fun onBindViewHolder(holder: CardTasarimNesneleriTutucu, position: Int) {
        val card = cardList[position]
        holder.cardTasarimBinding.myPetNesne = card
    }
}

同时Fragment中的Adapter初始化也同步调整:

adapter = MyPetsAdapter(requireContext(), myPetsList)

3. 验证Pet类序列化

确保Pet类有默认无参构造函数,且字段名与Firebase数据库中的键完全匹配(包括大小写):

data class Pet(
    val pet_name: String? = null,
    // 其他字段需对应Firebase中的键,且添加默认值
)

4. 确认布局绑定正确性

检查fragment_my_pets.xml中RecyclerView的adapter绑定是否正确:

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView"
    app:adapter="@{myPetsAdapter}"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

内容的提问来源于stack exchange,提问作者Mehmet Akif Çelebi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 07:54:54