NullPointerException - попытка вызвать виртуальный метод RecyclerView $ViewHolder.shouldIgnore() 'для ссылки на нулевой объект
Несколько разработчиков сообщили о следующей трассировке стека с момента обновления до 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)
Это происходит, когда включена анимация изменения RecyclerView, и вызываются соответствующие RecyclerView.Adapter методы notifyItemInserted(), notifyItemRemoved() и т.д., чтобы указать, что изолированное изменение было внесено в список, управляемый адаптером (в отличие от оптовые изменения, как указано notifyDataSetChanged()).
Это из-за ошибки в RecyclerView, или мы разработчики что-то не так?
Ответы
Ответ 1
Похоже, это связано с ошибкой в RecyclerView, которая была представлена в 23.2.0. Об этой ошибке сообщили здесь, и я объяснил, что, по моему мнению, является причиной ошибки в комментарии № 5 к этой ошибке.
Вот мое объяснение, скопированное сюда в исторических целях и для удобства пользования:
Я нашел источник этой проблемы. В RecyclerView.dispatchLayoutStep3() есть цикл for, "for (int я = 0; я <count; ++i)", где count основан на mChildHelper.getChildCount(). В то время как эта итерация происходит, коллекция, управляемая ChildHelper, модифицируется ChildHelper.hideViewInternal(), в результате чего null возвращается из вызова mChildHelper.getChildAt() в строке 3050 RecyclerView, что, в свою очередь, приводит к тому, что null возвращается из getChildViewHolderInt() в той же строке кода (RecyclerView: 3050).
Здесь цепочка вызовов методов, которая приводит к модификации, которая нарушает целостность цикла for:
dispatchLayoutStep3() → animateChange() → addAnimatingView() → hide() → hideViewInternal()
Когда ChildHelper добавляет дочерний параметр в свою коллекцию mHiddenViews, он нарушает целостность цикла for в dispatchLayoutStep3().
Я вижу два обходных пути для этого:
1) Отключить изменение анимации в вашем RecyclerView
2) Понижение до 23.1.1, где это не было проблемой
Ответ 2
В моем случае ошибка вызвана тем, что я устанавливал новый RecyclerView.LayoutParams в rootview элемента.
Затем я понял, что представления элементов RecyclerView фактически хранят свои ViewHolders в настраиваемом классе LayoutParams.
Поэтому, когда я reset ссылка LayoutParams ViewHolder исчезла навсегда. Это приводит к сбою NullPointerException позже.
Проблема исчезла после того, как я остановил настройку RecyclerView.LayoutParams в элементе rootView.:)
Так. Прекратите делать это в своем ViewHolder:
RecyclerView.LayoutParams params = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
itemRoot.setLayoutParams(params);
Ответ 3
Если вам абсолютно необходимо изменить параметры макета, вы можете использовать параметры макета по умолчанию, как это:
ViewGroup.LayoutParams params = itemView.getLayoutParams();
params.height=xx;
params.width= xx;
params.yyyy = xxx;
itemView.setLayoutParams(params);
Ответ 4
Я встретил это исключение только сейчас, и я исправил его, изменив framgent
на FragmentLayout
.
Мой адаптер использовал некоторые данные в аргументе фрагмента, а использование fragment
в xml не заполняет данные, поэтому возникает ошибка.
Просто отправьте это здесь, возможно, полезно кому-то.
Ответ 5
Я также столкнулся с этой проблемой, даже с версией RecyclerView 27.1.1. И у меня был следующий код в моем проекте:
recyclerView.setLayoutManager(mLayoutManager);
SimpleItemAnimator itemAnimator = new DefaultItemAnimator();
itemAnimator.setSupportsChangeAnimations(false);
recyclerView.setItemAnimator(itemAnimator);
LayoutInflater inflater = LayoutInflater.from(getContext());
И я исправил это после удаления добавления Animator в RecyclerView, то есть этот код начал выглядеть следующим образом:
recyclerView.setLayoutManager(mLayoutManager);
LayoutInflater inflater = LayoutInflater.from(getContext());
Ответ 6
Пожалуйста, убедитесь, что ваш layoutlerview находится не в дочернем layout.xml