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 } }
问题分析与解决方案
核心问题点
- 异步回调时序误解:你在
onCreateView中打印myPetsList.size时,Firebase的onDataChange回调还未执行(Firebase数据请求是异步的),此时列表确实为空,但数据后续会被正常添加,只是日志时机不对。 - 数据类型不兼容:Adapter构造函数接收
List<Pet?>,但你传入的是ArrayList<Pet>,后续updateItems传入List<Pet>赋值给cardList时存在隐式类型转换,可能导致数据绑定异常。 - 布局绑定验证缺失:未确认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
相关产品推荐
相关产品推荐

