我正在尝试使用嵌套的RecyclerView,其中Horizontal RecyclerView将显示为Vertical RecyclerView的项目。 (用户界面与Google Play商店类似)
由于我的数据集位于FirebaseFirestore中,因此我使用FirestoreRecyclerAdapter来实现此目的。
My Fragment的代码(此处存在Parent RecyclerView):
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val view = inflater.inflate(R.layout.layout_recyclerview, container, false)
val query = <some reference>
val recycler = view.recyclerView
recycler.setHasFixedSize(true)
adapter = DashboardAdapter(this,
FirestoreRecyclerOptions.Builder<Category>().categoryOption(query, this),
R.layout.item_dashboard_row)
recycler.adapter = adapter
return view
}
DashboardAdapter代码段:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DashboardHolder {
val item = LayoutInflater.from(parent.context)
.inflate(layout, parent, false)
return DashboardHolder(item)
}
DashboardHolder片段:
internal class DashboardHolder(item: View) : RecyclerView.ViewHolder(item) {
private val rowTitle: TextView = item.rowTitle
private val rowRecycler: RecyclerView = item.rowRecycler
fun bind(category: Category, owner: LifecycleOwner) {
rowTitle.text = category.name
rowRecycler.setHasFixedSize(true)
val query = <some query>
val adapter = DashboardProductsAdapter(
FirestoreRecyclerOptions.Builder<Product>()
.productOption(query, owner),
R.layout.item_dashboard_product)
rowRecycler.adapter = adapter
}
}
很明显,DashboardHolder(父视图持有者)中有RecyclerView。在绑定时,会创建子适配器并将其设置为子RecyclerView。
当我第一次加载Fragment时,一切正常并正确加载。但是,在我单击“主页”按钮并再次返回应用程序后,只会填充父级RecyclerView,而不是子级。
在我开始挖掘更多内容之后,发现这是因为LifecycleOwner
我在创建FirestoreRecyclerOptions
时正在通过。如果我没有设置它并手动调用startListening()
和stopListening()
,那么行为也是一样的。但如果我不打电话给stopListening()
,它就可以了。
更新了Fragment的代码:
override fun onStart() {
super.onStart()
adapter.startListening()
}
override fun onStop() {
super.onStop()
// If I comment this out, everything works fine
// But putting this in code doesn't populate the child RecyclerView 2nd time
adapter.stopListening()
}
可能出现什么问题?我应该在bind()方法之外创建子适配器吗?我应该跳过stopListening()
回调,但这可能会导致内存泄漏。
答案 0 :(得分:0)
我认为这里有几件事可能会出错。一旦我们弄明白,我就会更新这个答案。
首先,我想确保您在bind()
中呼叫onBindViewHolder()
,对吧?
接下来,我非常确定这不重要,但您可以将初始代码移动到onViewCreated()
,如下所示:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
inflater.inflate(R.layout.layout_recyclerview, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val query = <some reference>
val recycler = view.recyclerView
recycler.setHasFixedSize(true)
adapter = DashboardAdapter(this,
FirestoreRecyclerOptions.Builder<Category>().categoryOption(query, this),
R.layout.item_dashboard_row)
recycler.adapter = adapter
}
至于你的观点持有者,你需要解决的一个核心问题是思考这个问题有点棘手。在bind()
和onStart()
之间会多次调用onStop
,这意味着你会留下大量的挂起适配器,因为stopListening()
赢了&# 39;当适配器反弹时调用。要解决这个问题,您需要将适配器保存在属性中,并且每次都在bind()
中清除它,如下所示:
private var currentAdapter: FirestoreRecyclerAdapter<...>? = null
fun bind(...) {
currentAdapter?.let {
it.stopListening() // Stop listening to database
lifecycle.removeObserver(it) // Prevent automatic readdition of listeners
}
// Init adapter
currentAdapter = ...
}
如果上述方法都不起作用,您需要逐步逐步执行一些核心调试,直到看到事情分崩离析为止。这些是我建议添加的断点:
startListening()
方法,确保调用addChangeEventListener()
onChildChanged()
方法,确保使用正确的值调用onStop()
3.1.0
和AAC版本rc1
。