Подтвердить что ты не робот

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, или мы разработчики что-то не так?

4b9b3361

Ответ 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