嵌套的RecyclerView与FirestoreRecyclerAdapter和LifecycleOwner不会填充

时间:2017-10-21 03:51:05

标签: android android-recyclerview firebaseui google-cloud-firestore android-architecture-components

我正在尝试使用嵌套的RecyclerView,其中Horizo​​ntal 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()回调,但这可能会导致内存泄漏。

1 个答案:

答案 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 = ...
}

如果上述方法都不起作用,您需要逐步逐步执行一些核心调试,直到看到事情分崩离析为止。这些是我建议添加的断点:

  1. 适配器的startListening()方法,确保调用addChangeEventListener()
  2. 适配器的onChildChanged()方法,确保使用正确的值调用
  3. 走看堆栈以查看你的记忆并确保你所持有的参考是当前的对象,而不是来自onStop()
  4. 的鬼魂
  5. 一切都在正确的地方被召唤?可能不是FirebaseUI或架构组件问题。顺便说一句,确保您使用最新的FUI版本3.1.0和AAC版本rc1