使用 Firebase 实时数据库参考填充 RecyclerView
Posted
技术标签:
【中文标题】使用 Firebase 实时数据库参考填充 RecyclerView【英文标题】:Populate RecyclerView with Firebase Realtime Database References 【发布时间】:2021-12-29 22:31:27 【问题描述】:我正在尝试为HomeFragment
创建一个类别 RecyclerView,但在我的addValueEventListener
的onDataChange()
函数中设置我的类别和 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<String>()
无法编译,您可能需要将 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 实时数据库填充详细信息活动