web-dev-qa-db-fra.com

NullPointerException - Tentative d'appeler la méthode virtuelle RecyclerView $ ViewHolder.shouldIgnore () 'sur une référence d'objet null

Plusieurs développeurs ont signalé avoir vu la trace de pile suivante depuis la mise à niveau vers Android Support 23.2.0:

Java.lang.NullPointerException: Attempt to invoke virtual method 'boolean Android.support.v7.widget.RecyclerView$ViewHolder.shouldIgnore()' on a null object reference
    at Android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.Java:2913)
    at Android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.Java:1445)
    at Android.support.v7.widget.RecyclerView.access$400(RecyclerView.Java:144)
    at Android.support.v7.widget.RecyclerView$1.run(RecyclerView.Java:282)
    at Android.view.Choreographer$CallbackRecord.run(Choreographer.Java:821)
    at Android.view.Choreographer.doCallbacks(Choreographer.Java:606)
    at Android.view.Choreographer.doFrame(Choreographer.Java:575)
    at Android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.Java:807)
    at Android.os.Handler.handleCallback(Handler.Java:739)
    at Android.os.Handler.dispatchMessage(Handler.Java:95)
    at Android.os.Looper.loop(Looper.Java:145)
    at Android.app.ActivityThread.main(ActivityThread.Java:6895)
    at Java.lang.reflect.Method.invoke(Native Method)
    at Java.lang.reflect.Method.invoke(Method.Java:372)
    at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:1404)
    at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:1199)

Cela se produit lorsque l'animation de modification de RecyclerView est activée et que les méthodes RecyclerView.Adapter correspondantes notifyItemInserted (), notifyItemRemoved () etc. comme indiqué par notifyDataSetChanged ()).

Est-ce dû à un bogue dans RecyclerView, ou est-ce que nous, développeurs, faisons quelque chose de mal?

14
Mark McClelland

Cela semble être dû à un bogue dans RecyclerView, introduit dans 23.2.0. Le bogue a été rapporté ici , et j’ai expliqué ce qui, selon moi, est à l’origine de l’erreur dans commentaire n ° 5 sur ce bogue.

Voici mon explication, copiée ici à des fins historiques et pour plus de commodité:

J'ai trouvé la source de ce problème. Dans RecyclerView.dispatchLayoutStep3 (), il existe une boucle for ", pour (int i = 0; i <nombre; ++ i)", nombre à partir de mChildHelper.getChildCount (). Pendant que cette itération se produit, le fichier La collection gérée par ChildHelper est modifiée par ChildHelper.hideViewInternal (), ce qui entraîne le renvoi de null de l'appel à mChildHelper.getChildAt () à la ligne 3050 de RecyclerView, qui à son tour renvoie null à partir de getChildViewHolderInt () sur la même ligne de code (RecyclerView: 3050).

Voici la chaîne d'appels de méthode qui entraîne la modification que casse l'intégrité de la boucle for:

dispatchLayoutStep3 () -> animateChange () -> addAnimatingView () -> hide () -> hideViewInternal ()

Lorsque ChildHelper ajoute le paramètre enfant à sa collection mHiddenViews, il viole l’intégrité de la boucle for dans les hauteurs dispatchLayoutStep3 ().

Je vois deux solutions de contournement pour cela: 

1) Désactiver l'animation de changement dans votre RecyclerView

2) rétrograder à 23.1.1, ce qui n'était pas un problème

4
Mark McClelland

Dans mon cas, l'erreur causée parce que j'étais en train de définir un nouveau RecyclerView.LayoutParams dans la vue racine d'un élément.

Ensuite, j'ai réalisé que les vues d'élément RecyclerView stockaient leurs ViewHolders dans une classe LayoutParams personnalisée . Ainsi, lorsque je réinitialise la référence LayoutParams ViewHolder, elle est partie pour toujours. Ce qui provoque un crash NullPointerException plus tard.

Le problème a disparu une fois que j'ai arrêté de configurer RecyclerView.LayoutParams dans l'élément rootView. :)

Alors. Arrêtez de faire cela dans votre ViewHolder:

RecyclerView.LayoutParams params = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
itemRoot.setLayoutParams(params);
5
Evren Ozturk

Si vous avez absolument besoin de modifier les paramètres de présentation, vous pouvez utiliser les paramètres de présentation d'élément par défaut comme ceci:

    ViewGroup.LayoutParams params = itemView.getLayoutParams();
    params.height=xx;
    params.width= xx;
    params.yyyy = xxx;
    itemView.setLayoutParams(params);
3
hubert

J'ai rencontré cette exception tout à l'heure et je l'ai corrigée en remplaçant framgent par FragmentLayout.

Mon adaptateur a utilisé des données dans l'argument fragment et l'utilisation de fragment au format XML ne remplit pas les données.

Il suffit de poster ceci ici, peut-être utile à quelqu'un.

1
boileryao