使用 Firebase 实时数据库参考填充 RecyclerView

Posted

技术标签:

【中文标题】使用 Firebase 实时数据库参考填充 RecyclerView【英文标题】:Populate RecyclerView with Firebase Realtime Database References 【发布时间】:2021-12-29 22:31:27 【问题描述】:

我正在尝试为HomeFragment 创建一个类别 RecyclerView,但在我的addValueEventListeneronDataChange() 函数中设置我的类别和 categoryImage 时遇到问题。如何执行 for 循环以获取我的 job-category 引用下的所有引用?谢谢!

数据库参考

Category.kt

data class Category constructor(val category: String, val categoryImage: String)

CategoryAdapter.kt

class CategoriesAdapter(val category: ArrayList<Category>) : RecyclerView.Adapter<CategoriesAdapter.ViewHolder>() 

    override fun onBindViewHolder(holder: ViewHolder, position: Int) 
        holder?.bindCategory(category[position])
    

    override fun getItemCount(): Int 
        return category.count()
    

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder 
        val view = LayoutInflater.from(parent?.context).inflate(R.layout.category, parent, false)
        return  ViewHolder(view)
    

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) 

        val categoryName = itemView?.findViewById<TextView>(R.id.categoryNameTextView)
        val categoryImage = itemView?.findViewById<ImageView>(R.id.categoryImageView)

        fun bindCategory(category: Category) 

            categoryName?.text = category.category
            categoryImage?.setImageURI(category.categoryImage.toUri())

        

    


category.xml

<ImageView
   android:id="@+id/categoryImageView"
   android:layout_
   android:layout_
   android:background="@drawable/image_rounded_top_corners"
   android:scaleType="fitXY"
   app:layout_constraintEnd_toEndOf="parent"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintTop_toTopOf="parent"
   app:srcCompat="@drawable/profile_photo_"
   android:contentDescription="@string/category_image" />

<TextView
   android:id="@+id/categoryNameTextView"
   android:layout_
   android:layout_
   android:text="@string/category_name"
   android:textAlignment="center"
   android:textColor="@color/black"
   android:textSize="14sp"
   android:textStyle="bold"
   app:layout_constraintBottom_toBottomOf="parent"
   app:layout_constraintEnd_toEndOf="parent"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintTop_toBottomOf="@+id/categoryImageView" />

HomeFragment.kt

lateinit var categoriesAdapter: CategoriesAdapter

val categories = ArrayList Category ()  

val categoriesDatabaseRef = FirebaseDatabase.getInstance().reference.child(REF_JOB_CATEGORIES)

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? 

        val view: View = inflater.inflate(R.layout.fragment_home, container, false)

        categoriesAdapter = CategoriesAdapter(categories)


val popularCategoriesRecyclerView = view.findViewById<RecyclerView>(R.id.popularCategoriesRecyclerView)
    val layoutManager = GridLayoutManager(view.context, 3, GridLayoutManager.HORIZONTAL, false)
    popularCategoriesRecyclerView.layoutManager = layoutManager

    categoriesDatabaseRef.addValueEventListener(object: ValueEventListener 
        @SuppressLint("NotifyDataSetChanged")
        override fun onDataChange(snapshot: DataSnapshot) 
            categories.clear()
            for (snap in snapshot.children) 
                val category = Category(snap.child("category").getValue(String::class.java)!!,snap.child("categoryImage").getValue(String::class.java)!!)
                categories.add(category)
            
            categoriesAdapter.notifyDataSetChanged()
        

        override fun onCancelled(error: DatabaseError) 
            Log.d("HomeFragment", "LoadPost:onCancelled", error.toException())
        
    )

        return view
    

Logcat 错误

 Process: com.zwdalpha.skedaddle, PID: 19898
    java.lang.IllegalArgumentException: Span count should be at least 1. Provided 0
        at androidx.recyclerview.widget.GridLayoutManager.setSpanCount(GridLayoutManager.java:829)
        at androidx.recyclerview.widget.GridLayoutManager.<init>(GridLayoutManager.java:86)
        at com.zwdalpha.skedaddle.Fragments.HomeFragment.onCreateView(HomeFragment.kt:74)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2963)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:518)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
        at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3128)
        at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:3065)
        at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2988)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:546)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
        at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3128)
        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3072)
        at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
        at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:502)
        at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:246)
        at com.zwdalpha.skedaddle.MainActivity.onStart(MainActivity.kt:36)
        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1391)
        at android.app.Activity.performStart(Activity.java:7157)
        at android.app.ActivityThread.handleStartActivity(ActivityThread.java:2937)
        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

【问题讨论】:

你确定你没有收到关于没有“无参数构造函数”的错误吗? 添加了我的 logcat 错误,谢谢你的帮助 @ZacharySmouse 看起来您在snapshot.children 上实现了以下答案建议的循环,然后遇到了一个新问题。不要以使这些答案无效的方式修改现有问题中的代码,请确认答案(请参阅What should I do when someone answers my question?)并考虑在新问题中发布新问题。 【参考方案1】:

只需将此代码放在 categories.clear() 之后

for (snap in snapshot.children)
     val category = snap.getValue(Category::class.java)

//Here is Other Option To create category object without creating no-arg con
//val category = Category(snap.child("category").getValue(String::class.java)!!,snap.child("categoryImage").getValue(String::class.java)!!)
     categories.add(category)

你可以这样列出清单

【讨论】:

我将您的代码添加到我的问题中。但是我有一个问题,为什么我的应用会尝试在模拟器上打开但添加此代码时会关闭? 你能在你的 logcat 中添加什么错误显示吗? 是的,Alex 提到了您的错误,您必须在类别模型类中添加无参数构造函数。或者将默认值添加到您的模型类参数中,这可能会起作用,或者您可以为此使用普通类 我添加了我的 logcat 错误。我也包含了你的代码,我觉得我几乎拥有它,但我不知道我可能会错过什么 哦,天哪,错误本身会告诉您出了什么问题。当您创建布局管理器时,请提供像这样的 2 或 3 或 4 之类的修复跨度计数。那里间接为您提供 0。在您的代码中 categories.count() 替换为一些修复编号【参考方案2】:

你已经很接近了。在您的onDataChange 中,您需要循环遍历snapshot.children,然后获取每个属性的值。

Kotlin 不是我的强项,但它应该是这样的:

categoriesDatabaseRef.addValueEventListener(object: ValueEventListener 
    @SuppressLint("NotifyDataSetChanged")
    override fun onDataChange(snapshot: DataSnapshot) 
        categories.clear()

        for (snapshot in dataSnapshot.children)  // ? loop over children
            categories.add(snapshot.child("category").getValue<String>(); // ? get value
        

        categoriesAdapter.notifyDataSetChanged()
    

    override fun onCancelled(error: DatabaseError) 
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException()) // ? never ignore errors
    
)

如果 getValue&lt;String&gt;() 无法编译,您可能需要将 Firebase 实时数据库的 ktx 扩展添加到您的 Gradle 文件中,或使用 snapshot.child("category").getValue(String::class.java)

另请参阅 listening for children through a value event 和 reading a value 上的 Firebase 文档。

【讨论】:

以上是关于使用 Firebase 实时数据库参考填充 RecyclerView的主要内容,如果未能解决你的问题,请参考以下文章

单击 RecyclerView 后使用 Firebase 实时数据库填充详细信息活动

FireBase 实时数据库:回收站视图未填充

使用 Firebase 数据填充集合视图

如何在flutter中从firebase数据填充listview

反应本机 firebase 实时数据库参考返回 null

在 onBindViewHolder 中为 RecyclerView 设置 Firebase 实时数据库参考中的图像