【问题标题】:Nested RecyclerView with FirestoreRecyclerAdapter and LifecycleOwner doesn't populate带有 FirestoreRecyclerAdapter 和 LifecycleOwner 的嵌套 RecyclerView 不会填充
【发布时间】:2017-10-21 03:51:04
【问题描述】:

我试图有一个嵌套的 RecyclerView,其中水平 RecyclerView 将显示为 Vertical RecyclerView 的一个项目。 (用户界面类似于 Google Play 商店)

由于我的数据集在 FirebaseFirestore 中,因此我使用 FirestoreRecyclerAdapter 来实现此目的。

我的 Fragment 的代码(这里有父 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 sn-p:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DashboardHolder {
    val item = LayoutInflater.from(parent.context)
            .inflate(layout, parent, false)
    return DashboardHolder(item)
}

DashboardHolder sn-p:

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() 回调,但这可能会导致内存泄漏。

【问题讨论】:

  • 嗨@Chandra Sekhar,我在使用Firestore RecyclerView时遇到了同样的问题,在我的情况下,我在父RecyclerView的onBindViewHolder中调用嵌套回收器视图的adapter.startListening()并且从不调用adapter.stopListening( )。该应用程序可以正常工作一段时间,但开始挂起并最终崩溃,我认为这可能是因为多次调用 adapter.startListening() 而没有停止导致内存泄漏。你有没有找到任何解决方案。任何帮助将不胜感激。

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


【解决方案1】:

我认为这里有几件事可能会出错。一旦我们弄清楚了,我会更新这个答案。

首先,我想确保您在onBindViewHolder() 中拨打bind(),对吗?

接下来,我很确定这无关紧要,但您能否像这样将您的初始化代码移动到 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()。为了解决这个问题,您需要将您的适配器保存在一个属性中,并每次在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. 是否在正确的位置调用了所有内容?可能不是 FirebaseUI 或架构组件问题。顺便说一句,确保您使用的是最新的 FUI 版本 3.1.0 和 AAC 版本 rc1

【讨论】:

  • 最新 FUI 出现以下异常:java.lang.RuntimeException: java.lang.NoSuchMethodException: [class com.firebase.ui.firestore.FirestoreRecyclerAdapter] at android.arch.lifecycle.j.a( Lifecycling.java:111) 在 android.arch.lifecycle.j.a(Lifecycling.java:57) 在 android.arch.lifecycle.h$a.(LifecycleRegistry.java:346) 在 android.arch.lifecycle.h.a (LifecycleRegistry.java:162) 在 com.firebase.ui.firestore.FirestoreRecyclerAdapter.(FirestoreRecyclerAdapter.java:37)
  • 嗯,这似乎是一个完全不同的问题。确保您使用的是支持库 26.1.x 并尝试运行 ./gradlew clean。不知道那里会发生什么。
  • 是的,支持库是 26.1.0 并且已经尝试清理项目。我的应用程序仅使用带有 FUI 3.0.0 的 arch-components 1.0.0-beta1 运行。每当我尝试更新其中任何一个时,它都会开始崩溃。
  • 嗯,你能用反混淆的堆栈跟踪创建一个 GitHub 问题吗?
  • 它只发生在启用了 proguard 的 apk 中。请参阅此问题的最后一条评论。 github.com/firebase/FirebaseUI-Android/issues/46
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-23
  • 1970-01-01
  • 2016-04-19
  • 2019-04-18
  • 2017-03-20
  • 2020-06-07
  • 1970-01-01
相关资源
最近更新 更多