使用 Firebase 实时数据库引用填充 RecyclerView

Populate RecyclerView with Firebase Realtime Database References

我正在尝试为 HomeFragment 创建类别 RecyclerView,但在 addValueEventListeneronDataChange() 函数中设置类别和类别图像时遇到问题。我怎样才能做一个 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_width="420dp"
   android:layout_height="676dp"
   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_width="wrap_content"
   android:layout_height="wrap_content"
   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)

你很接近。在您的 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<String>() 无法编译,您可能需要将 Firebase 实时数据库的 ktx 扩展添加到 Gradle 文件,或使用 snapshot.child("category").getValue(String::class.java)

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

只需将此代码放在 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)
}

你可以这样列单