0

J'essaie d'avoir un RecyclerView imbriqué où un RecyclerView horizontal sera affiché comme un élément de Vertical RecyclerView. (L'interface utilisateur ressemble à Google Play Store)RecyclerView imbriqué avec FirestoreRecyclerAdapter et LifecycleOwner ne remplit pas

Depuis que mon jeu de données est dans FirebaseFirestore, j'utilise FirestoreRecyclerAdapter pour y parvenir.

Code de mon Fragment (Parent RecyclerView existe ici):

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 extrait:

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

extrait de 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 
} 
} 

Il est clair que DashboardHolder (le titulaire de la vue parent) a RecyclerView dedans. Et pendant la liaison, l'adaptateur enfant est créé et défini sur l'enfant RecyclerView.

Lorsque je charge le fragment pour la première fois, tout fonctionne correctement et se charge correctement. Mais après avoir cliqué sur le bouton Accueil et revenir à l'application, seul le parent RecyclerView est rempli, pas les enfants. Après avoir commencé à creuser plus, j'ai compris que c'était à cause de LifecycleOwner que je passe en créant FirestoreRecyclerOptions. Si je ne le mets pas et appelez manuellement startListening() et stopListening(), alors le comportement est le même. Mais si je n'appelle pas stopListening(), cela fonctionne très bien.

Mise à jour le code de 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() 
} 

Quel pourrait être le problème possible? Dois-je créer l'adaptateur enfant en dehors de la méthode bind()? Dois-je ignorer le rappel stopListening(), mais cela peut entraîner une fuite de mémoire.

Répondre

0

Je pense qu'il y a plusieurs choses qui pourraient mal se passer ici. Je mettrai à jour cette réponse une fois que nous l'aurons trouvée.

Tout d'abord, je veux être sûr que vous appelez bind() en onBindViewHolder(), non?

Ensuite, je suis assez sûr que cela n'a pas d'importance, mais pourriez-vous déplacer votre code d'initialisation à onViewCreated() comme ceci:

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 
} 

En ce qui concerne vos supports de vue, il y a un problème de base dont vous aurez besoin résoudre ce qui est un peu difficile à penser. bind() va être appelé à plusieurs reprises entre onStart() et onStop ce qui signifie que vous allez être laissé avec un grand nombre de cartes suspendues, car stopListening() ne sera pas appelé quand un adaptateur est rebond. Pour contourner ce problème, vous devrez enregistrer votre adaptateur dans une propriété et l'effacer à chaque fois dans bind() comme ceci:

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

Si aucun des travaux ci-dessus, vous aurez besoin de faire du débogage Hardcore parcourir votre code petit à petit jusqu'à ce que vous voyiez où les choses tombent en morceaux.Ce sont les points d'arrêt, je suggère d'ajouter:

  1. méthode startListening() de l'adaptateur, assurez-vous addChangeEventListener() est appelé
  2. méthode onChildChanged() de l'adaptateur, assurez-vous qu'il est appelé avec les valeurs correctes
  3. Marchez la pile de regarder à travers votre mémoire et assurez-vous que les références que vous tenez sont les objets courants et non les fantômes de onStop()
  4. Tout est appelé au bon endroit? Probablement pas un problème FirebaseUI ou composants d'architecture. BTW, assurez-vous que vous êtes sur la dernière version FUI 3.1.0 et la version AAC rc1.
+0

Ci-dessous exception avec la dernière FUI: java.lang.RuntimeException: java.lang.NoSuchMethodException: [com.firebase.ui.firestore.FirestoreRecyclerAdapter class] à android.arch.lifecycle.ja (Lifecycling.java: 111) at android.arch.lifecycle.ja (Lifecycling.java:57) à android.arch.lifecycle.h $ a. (LifecycleRegistry.java:346) at android.arch.lifecycle.h.a (LifecycleRegistry.java:162) à com.firebase.ui.firestore.FirestoreRecyclerAdapter. (FirestoreRecyclerAdapter.java:37) –

+0

Hmmm, cela semble être un problème tout à fait différent. Assurez-vous que vous utilisez support lib 26.1.x et essayez d'exécuter './gradlew clean'. Je ne sais pas ce qui pourrait aller là-bas. – SUPERCILEX

+0

Oui la bibliothèque de support est 26.1.0 et a déjà essayé le projet de nettoyage. Mon application fonctionne uniquement avec arch-components 1.0.0-beta1 avec FUI 3.0.0. Chaque fois que j'essaie de mettre à jour l'un d'entre eux, il commence à s'écraser. –