Kotlin中Firebase实时数据库数据无法在RecyclerView显示求助
Firebase实时数据库数据无法显示在RecyclerView
尝试将Firebase实时数据库groupNotice/(userId)路径下的数据展示到RecyclerView中,但数据始终无法加载显示。程序运行无报错,已尝试修改数据库引用路径、调整RecyclerView宽高设置,仍未解决。
相关代码
fragment_group_notice.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/GroupNoticeFragment" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".groupTab.groupNotices.GroupNoticesFragment"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/groupNoticeListRecycler" android:layout_width="match_parent" android:layout_height="wrap_content" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"> </androidx.recyclerview.widget.RecyclerView> </FrameLayout>
card_group_notice.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:background="@color/primary_green" android:orientation="horizontal" android:padding="10dp"> <TextView android:id="@+id/NoticeNameCard" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Notice Name" android:textColor="@color/pure_white" android:textSize="25sp" /> </LinearLayout> </layout>
GroupNoticesFragment.kt
class GroupNoticesFragment : Fragment() { private var _binding: FragmentGroupNoticesBinding? = null private val binding get() = _binding!! private lateinit var recycler: RecyclerView private var adapter: NoticeAdapter?= null private lateinit var viewModel: NoticeViewModel override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { container?.removeAllViews() _binding = FragmentGroupNoticesBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) recycler = binding.groupNoticeListRecycler recycler.layoutManager = LinearLayoutManager(context) recycler.setHasFixedSize(true) adapter = NoticeAdapter() recycler.adapter = adapter viewModel = ViewModelProvider(this)[NoticeViewModel::class.java] viewModel.allNotices.observe(viewLifecycleOwner) { adapter!!.updateNoticeList(it) } } }
NoticeAdapter.kt
class NoticeAdapter : RecyclerView.Adapter<NoticeAdapter.NoticeViewHolder>() { private val notices = ArrayList<GroupNoticeData>() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoticeViewHolder { val itemView = LayoutInflater.from(parent.context).inflate( R.layout.card_group_notices, parent, false ) return NoticeViewHolder(itemView) } override fun onBindViewHolder(holder: NoticeViewHolder, position: Int) { val currentNotice = notices[position] holder.noticeName.text = currentNotice.taskName } override fun getItemCount(): Int { return notices.size } fun updateNoticeList(notice: List<GroupNoticeData>) { this.notices.clear() this.notices.addAll(notice) notifyDataSetChanged() } class NoticeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val noticeName: TextView = itemView.findViewById(R.id.NoticeNameCard) } }
GroupNoticeData.kt
data class GroupNoticeData( val userId: String, val taskName: String, val taskDescription: String, val taskDate: String, val path: String?, val groupId: String ) { fun toMap(): Map<String, Any?> { return mapOf( "userId" to userId, "taskName" to taskName, "taskDescription" to taskDescription, "taskDate" to taskDate, "path" to path, "groupId" to groupId ) } }
NoticeViewModel.kt
class NoticeViewModel : ViewModel() { private val repository : NoticeRepo = NoticeRepo().getInstance() private val _allNotices = MutableLiveData<List<GroupNoticeData>>() val allNotices : LiveData<List<GroupNoticeData>> = _allNotices init { repository.loadNotices(_allNotices) } }
NoticeRepo.kt
class NoticeRepo{ val auth = Firebase.auth val user = auth.currentUser!!.uid private val noticeReference : DatabaseReference = FirebaseDatabase.getInstance().getReference("groupNotice").child(user) @Volatile private var INSTANCE : NoticeRepo?= null fun getInstance(): NoticeRepo { return INSTANCE ?: synchronized(this) { val instance = NoticeRepo() INSTANCE = instance instance } } fun loadNotices(allNoticeList: MutableLiveData<List<GroupNoticeData>>) { noticeReference.addValueEventListener(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { try { val noticeList : List<GroupNoticeData> = snapshot.children.map { dataSnapshot -> dataSnapshot.getValue(GroupNoticeData::class.java)!! } allNoticeList.postValue(noticeList) }catch (_: Exception){ } } override fun onCancelled(error: DatabaseError) { TODO("Not yet implemented") } }) } }
问题排查与修复方案
1. 数据类添加无参构造函数
Firebase反序列化Kotlin数据类必须依赖无参构造,否则无法将Snapshot转换为实体类。修改GroupNoticeData.kt:
data class GroupNoticeData( val userId: String = "", val taskName: String = "", val taskDescription: String = "", val taskDate: String = "", val path: String? = null, val groupId: String = "" ) { fun toMap(): Map<String, Any?> { return mapOf( "userId" to userId, "taskName" to taskName, "taskDescription" to taskDescription, "taskDate" to taskDate, "path" to path, "groupId" to groupId ) } }
2. 修正单例模式实现
原NoticeRepo的单例逻辑错误,导致数据库引用重复初始化,且未处理用户未登录场景。修改NoticeRepo.kt:
class NoticeRepo private constructor() { private lateinit var noticeReference: DatabaseReference private val auth = Firebase.auth init { auth.currentUser?.let { user -> noticeReference = FirebaseDatabase.getInstance().getReference("groupNotice").child(user.uid) } ?: run { Log.e("NoticeRepo", "用户未登录,无法初始化数据库引用") } } companion object { @Volatile private var INSTANCE: NoticeRepo? = null fun getInstance(): NoticeRepo { return INSTANCE ?: synchronized(this) { val instance = NoticeRepo() INSTANCE = instance instance } } } fun loadNotices(allNoticeList: MutableLiveData<List<GroupNoticeData>>) { if (!::noticeReference.isInitialized) return noticeReference.addValueEventListener(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { try { val noticeList = snapshot.children.mapNotNull { it.getValue(GroupNoticeData::class.java) } allNoticeList.postValue(noticeList) Log.d("NoticeRepo", "成功加载${noticeList.size}条通知") } catch (e: Exception) { Log.e("NoticeRepo", "解析通知失败", e) } } override fun onCancelled(error: DatabaseError) { Log.e("NoticeRepo", "数据库加载取消", error.toException()) } }) } }
3. 修正Adapter布局引用
NoticeAdapter中加载的布局ID与实际布局文件名不匹配,修改为正确的ID:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoticeViewHolder { val itemView = LayoutInflater.from(parent.context).inflate( R.layout.card_group_notice, // 修正布局ID parent, false ) return NoticeViewHolder(itemView) }
4. 调整RecyclerView高度
将RecyclerView高度改为match_parent,避免wrap_content导致数据加载后无法显示:
<androidx.recyclerview.widget.RecyclerView android:id="@+id/groupNoticeListRecycler" android:layout_width="match_parent" android:layout_height="match_parent" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"> </androidx.recyclerview.widget.RecyclerView>
内容的提问来源于stack exchange,提问作者Parvez Ahammed
相关产品推荐
相关产品推荐

