RecyclerView вылетает, когда «утилизированные или прикрепленные виды не могут быть переработаны»

Я использую простую реализацию RecyclerView взятую с веб-сайта Android, используя StaggeredGridLayoutManager и я продолжаю получать эту ошибку, которая приводит к StaggeredGridLayoutManager моего приложения:

 java.lang.IllegalArgumentException: Scrapped or attached views may not be recycled. isScrap:false isAttached:true at android.support.v7.widget.RecyclerView$Recycler.recycleViewHolderInternal(RecyclerView.java:3501) at android.support.v7.widget.RecyclerView$LayoutManager.scrapOrRecycleView(RecyclerView.java:5355) at android.support.v7.widget.RecyclerView$LayoutManager.detachAndScrapAttachedViews(RecyclerView.java:5340) at android.support.v7.widget.StaggeredGridLayoutManager.onLayoutChildren(StaggeredGridLayoutManager.java:572) at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:1918) at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:2155) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1021) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.support.v7.internal.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:502) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1663) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1521) at android.widget.LinearLayout.onLayout(LinearLayout.java:1434) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.widget.FrameLayout.onLayout(FrameLayout.java:448) at android.view.View.layout(View.java:14008) at android.view.ViewGroup.layout(ViewGroup.java:4373) at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1892) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1711) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:989) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4351) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749) at android.view.Choreographer.doCallbacks(Choreographer.java:562) at android.view.Choreographer.doFrame(Choreographer.java:532) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5041) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at dalvik.system.NativeStart.main(Native Method) 

Простым, я буквально подразумеваю, что это та же самая реализация, взятая с этой страницы на их веб-сайте , единственное различие заключается в том, что мой макет элемента сетки – это ImageView и пара TextView , поэтому я не буду беспокоиться о повторном копировании моего кода.

Кто-нибудь еще получает эту ошибку и знает, как с этим бороться?

Эта ошибка возникает, если в вашем XML есть android:animateLayoutChanges установлен в true, и вы вызываете notifyDataSetChanged() в адаптере RecyclerView в коде Java.

Поэтому просто избегайте использования android:animateLayoutChanges с RecyclerViews.

Мне тоже пришлось иметь дело с этой катастрофой, и в моем случае это не имело никакого отношения к android:animateLayoutChanges .

У RecyclerView мы строили, было более одного типа взглядов в нем, а некоторые из них имели в них EditText . Через некоторое время мы прикрепили вопрос к тому, чтобы быть связанным с фокусом. Эта ошибка возникает при утилизации EditText s, и одна из них сфокусирована.

Естественно, мы попытались очистить фокус, когда новые данные привязаны к переработанному представлению, но это не сработало, пока android:focusableInTouchMode="true" не установлен в RecycleView . На самом деле это единственное изменение, которое было необходимо для завершения этой проблемы.

Я удалил android:animateLayoutChanges из свойства макета и проблема была решена.

Среди причин, по которым любой может столкнуться с этой проблемой, проверьте, установлен ли атрибут android:animateLayoutChanges="true" для RecyclerView. Это приведет к сбою и повторному подключению элементов RecyclerView. Удалите его и назначьте атрибут родительскому контейнеру RecyclerView, например LinearLayout / RelativeLayout, и вы увидите, что проблема исчезнет.

При использовании slimfit липких заголовков я столкнулся с этой ошибкой. Это было вызвано неправильной первой позицией. Я получил ответ здесь

 public void onBindViewHolder(MainViewHolder holder, int position) { final View itemView = holder.itemView; final LayoutManager.LayoutParams params = LayoutManager.LayoutParams.from(itemView.getLayoutParams()); params.setSlm(LinearSLM.ID); params.width = ViewGroup.LayoutParams.MATCH_PARENT; params.setFirstPosition(item.mSectionFirstPosition); itemView.setLayoutParams(params); } 

просто убедитесь, что вы передаете правильное значение для mSectionFirstPosition

Мне потребовалось два дня, но я не мог обойти это, в конце концов, мне пришлось отключить предварительную выборку.

При настройке диспетчера компоновки вы можете просто позвонить

mGridLayoutManager.setItemPrefetchEnabled(false);

Это заставило меня уйти. Надеюсь, это будет полезно для кого-то.

Сегодня утром я встретил эту проблему, но я не сталкиваюсь с той же причиной, о которой говорилось выше.

Через debug я обнаружил, что представление элемента в моем ViewHolder имеет mParent и оно не является нулевым, что в нормальном случае оно не должно быть ничем (это то, что говорит журнал, «прикрепленное представление не может быть переработано», я думаю, это означает, что если ребенок представление уже привязано к родительскому объекту, это может привести к сбою при повторном использовании.)

Но я не привязывал просмотр ребенка каждый раз вручную. И я обнаружил, что это делается, когда я пытаюсь раздуть детское представление в моем ViewHolder, что-то вроде:

 layoutInflater.inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) 

И последний параметр attachToRoot должен быть ложным.

После того, как я изменил его на false , я исправил свою проблему.

Кстати, я вижу, что этот сбой произошел, когда я обновляю свою библиотеку поддержки до последней версии 25.0.0. До того, как я использовал версию 23.4.0, и я не вижу этой проблемы. Я думаю, что в последней библиотеке поддержки должно быть что-то изменилось.

Надеюсь, эта помощь.

Я parent.addView() эту проблему, удаляя parent.addView() в onCreateViewHolder

Это мой код

 public MyViewHolder onCreateViewwHolder(ViewGroup parent, int viewType) { Button addButton = new Button(context); //parent.addView(addButton); return new MyViewHolder(addButton); } 

Функция в android.support.v7.widget.RecyclerViewRecycler.recyclerViewHolderinternal() проверить, имеет ли моя кнопка уже родительский или нет. Что, если мы добавим кнопку в родительский mParent , она также будет назначать RecyclerView своей переменной mParent .

В моем случае это произошло из-за того, что у меня было Transition выполнение при попытке resize RecyclerView, потому что клавиатура программного обеспечения собиралась показать.

Я исправил его, исключая RecyclerView из Transition , используя Transition.excludeTarget(R.id.recyclerview, true);

Я решил эту проблему, позвонив

 setHasStableIds(true); 

в конструкторе адаптера и переопределении getItemId в адаптере:

 @Override public long getItemId(int position) { return position; } 

Я видел, как это произошло для меня, когда я использовал пользовательский объект в ViewHolder для адаптера RecyclerView .

Чтобы исправить проблему, я очистил пользовательский объект, который в моем случае был таймером в onViewRecycled(ViewHolder holder) для адаптера, как onViewRecycled(ViewHolder holder) ниже:

  public void onViewRecycled(ViewHolder holder) { if(holder instanceof EntityViewHolder) { if(((EntityViewHolder)holder).timer != null) { ((EntityViewHolder) holder).timer.cancel(); } } super.onViewRecycled(holder); } 

Это исправило ошибку.

  /** * Informs the recycler whether this item can be recycled. Views which are not * recyclable will not be reused for other items until setIsRecyclable() is * later set to true. Calls to setIsRecyclable() should always be paired (one * call to setIsRecyclabe(false) should always be matched with a later call to * setIsRecyclable(true)). Pairs of calls may be nested, as the state is internally * reference-counted. * * @param recyclable Whether this item is available to be recycled. Default value * is true. * * @see #isRecyclable() */ public final void setIsRecyclable(boolean recyclable) { mIsRecyclableCount = recyclable ? mIsRecyclableCount - 1 : mIsRecyclableCount + 1; if (mIsRecyclableCount < 0) { mIsRecyclableCount = 0; if (DEBUG) { throw new RuntimeException("isRecyclable decremented below 0: " + "unmatched pair of setIsRecyable() calls for " + this); } Log.e(VIEW_LOG_TAG, "isRecyclable decremented below 0: " + "unmatched pair of setIsRecyable() calls for " + this); } else if (!recyclable && mIsRecyclableCount == 1) { mFlags |= FLAG_NOT_RECYCLABLE; } else if (recyclable && mIsRecyclableCount == 0) { mFl`enter code here`ags &= ~FLAG_NOT_RECYCLABLE; } if (DEBUG) { Log.d(TAG, "setIsRecyclable val:" + recyclable + ":" + this); } } 

1, remove : удалите данные из списка.

2, notifyDataSetChanged : notifyDataSetChanged ();

3, notifyItemRemoved : показать анимацию.

4, notifyItemRangeChanged : размер диапазона размеров и перерисовать viewHolders(onBindViewHolder methods)

это исключение не является причиной

андроид: animateLayoutChanges

или

андроид: focusableInTouchMode

этот окончательный правильный ответ объясняется только тем, что вы устанавливаете WRONG LayoutParams .

  nameLP = new LinearLayout.LayoutParams(context.getResources().getDisplayMetrics().widthPixels, LinearLayout.LayoutParams.WRAP_CONTENT); nameLP2 = new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT); 

nameLP в порядке. имяLP2 происходит сбой .bug здесь.

Я пробую все ответы на эту страницу. Доверьтесь мне.

Я использую com.squareup.picasso.RequestCreator

 public void into(android.widget.ImageView target, Callback callback) 

для динамического изменения размера ImageView после загрузки изображения из Интернета и сохранения измененной ширины и высоты для сохранения размера представления. Я получил это исключение, потому что я сохранил LayoutParams на Map , и в моем onBindViewHolder я получил его и напрямую установил в свой ImageView . Я исправлю это с помощью ImmutablePair чтобы хранить только размер ImageView, а не много других состояний, и использовать следующий код для его восстановления.

 ViewGroup.LayoutParams params = image.getLayoutParams(); params.width = widthAndHeight.getLeft(); params.height = widthAndHeight.getRight(); image.setLayoutParams(params); 

Для меня такая же ошибка, вызванная LayoutTransition на более высоком уровне ViewGroup.

Позвольте мне добавить еще одно возможное решение для такого рода вопросов, пожалуйста. У меня была такая же проблема с библиотекой superSlim для липких заголовков в RecyclerView . Я использовал MatrixCursor для установки данных в RecyclerViewCursorAdapter . Причиной этой проблемы были столбцы ID равными 0 для всех заголовков. Надеюсь, что это поможет кому-то сохранить пару дней отладки.

В моем случае проблема была public long getItemId(int position) с неправильной реализацией этого метода public long getItemId(int position) (переопределяется из метода RecyclerView.Adapter ).

Старый код получит два разных идентификатора для одного и того же элемента (в моем случае это элемент нижнего колонтитула), после устранения проблемы проблема исчезла.

В моем случае я использовал TransitionManager.beginDelayedTransition() перед добавлением представления поверх recyclerView. Я удалил TransitionManager.beginDelayedTransition() и не разбился.

Обходное решение, если причина исключения – это то, что itemView имеет родительский элемент. В коде, где у вас есть notifyItemRemoved (position), удалите itemView из RecyclerView:

 View itemView = mRecyclerView.getLayoutManager().findViewByPosition(position); if (itemView != null && itemView.getParent() != null) { ((ViewGroup) itemView.getParent()).removeView(itemView); } notifyItemRemoved(position); 

Удалить android:animateLayoutChanges="true" из recycleview или установить android:animateLayoutChanges="false"

Случай, который произошел для меня, состоял в том, что у меня был член вида в адаптере, и я ленился, создавая представление, которое не нужно делать с видом перекопа.

Это также противоречит принципам перекодировки, которые в этом случае сохраняют ссылку на представление. Ниже приведен краткий пример:

 // typically we would do this in a grid view adapter: View v; // ... if(v = null){ v = LayoutInflater.inflate ...; } // Now with recycle view there is NO need to store a reference to View // and lazy instantiate. So get rid of your View v member 

Хотя в моем случае он animateOnLayoutChange из recyclerView, который исправил сбой, мне все еще нужна была возможность анимировать изменения макета в viewHolder. Чтобы заставить это работать, LinearLayout' in the view holder needs the animateOnLayoutChange’ to true, но мне нужно было notifyItemChanged для адаптера. Затем это позволяло запускать анимацию layoutTransition (для расширения и свертывания viewHolder), а также избегало отмененного исключения. Поэтому да, избегайте помещать animateOnLayoutChange в recylcerView и используйте различные методы уведомления, чтобы включить анимацию по умолчанию при изменении размера вида.

  • Расширяемый список с RecyclerView?
  • RecyclerView прокручивал прослушиватель UP / DOWN
  • Как узнать, прокручивается ли RecyclerView / LinearLayoutManager сверху или снизу?
  • Как создать круговой (бесконечный) RecyclerView?
  • Несоответствие обнаружено в RecyclerView, Как изменить содержимое RecyclerView при прокрутке
  • Android RecyclerView с GridLayoutManager делает диапазон элементов несколькими рядами
  • Как обновить данные адаптера RecyclerView?
  • Одиночный выбор в RecyclerView
  • Получение видимых элементов в RecyclerView
  • Давайте будем гением компьютера.