2014-10-21 2 views
67

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

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) 

Простым, я буквально подразумеваю, что это одна и та же реализация, взятая с this page on their website, с той лишь разницей, что мой макет элемента сетки - это ImageView и пара TextView s, поэтому я не буду перепробовать мой код.

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

+0

У вас есть решение? –

ответ

131

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

Итак, не используйте android:animateLayoutChanges с RecyclerViews.

+9

, то как можно использовать функцию animateLayoutChanges в recyclerview? – dhuma1981

+0

Что вы пытаетесь достичь? Элемент анимации? Если это так, API RecyclerView поддерживает это: ознакомьтесь с документацией: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html – Kenneth

+2

@ dhuma1981, если аниматор элемента установлен через mRecyclerView .setItemAnimator (новый DefaultItemAnimator()); то animateLayoutChanges не обязательно должно быть истинным. –

38

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

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

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

+1

Фантастические, решенные проблемы с несколькими фокусами, которые были у меня при использовании EditTexts в RecyclerView. Благодаря! –

+1

У меня был ACET в recyclerview, и он раздавит. Этот пост спас меня. –

+0

И у меня нет edittexts в элементах, но у меня есть флажки. должен ли я попробовать 'android: focusableInTouchMode =" true ", потому что это случается только иногда на некоторых устройствах (редко), и я предполагаю, что это не относится к моей проблеме, но трассировка стека для сбоя почти такая же. – Shivansh

0

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

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

// 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 
1

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

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

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

Это исправлена ​​ошибка.

8

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

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

+0

Добро пожаловать в StackOverflow. Не могли бы вы предоставить полный ответ, а не только ссылку? – slfan

+0

Отличный ответ. Это сработало для меня. Благодаря! – rrdev

+0

Что такое 'item' здесь? –

18

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

+0

Я начал получать этот крах, когда я разместил «android: animateLayoutChanges» на моем RV. – Mauker

+0

Если этот флаг установлен в родительском контейнере (относительная компоновка). Исправлена ​​проблема. – 1911z

0

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

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

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

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

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

0

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

6

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

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

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

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

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

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

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

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

+0

Это решение для меня, спасибо. – MHogge

3

я решить эту проблему путем удаления 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() проверки, имеет ли моя кнопка уже родитель или нет. Который, если мы добавим кнопку к родительскому, будет также назначать RecyclerView переменной mParent.

+0

Я думаю, что это новое требование, я присоединился к родителям в версии 24 поддержки библиотеки, после обновления до 25 я получил сбой. –

1
/** 
    * 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

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

2, notifyDataSetChanged: notifyDataSetChanged();

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

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

+0

Я удалил 'notifyItemRemoved' при удалении ошибок' footer' и приложений, изменив их на 'notifyDataSetChanged', и теперь он работает нормально. спасибо – user5599807

0

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

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

7

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

0

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

1

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

setHasStableIds(true); 

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

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

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

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

mGridLayoutManager.setItemPrefetchEnabled(false);

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

+0

Превосходный чувак. он работает для меня –

+0

он тоже работает для меня –

+0

Работал для меня. Благодарю. – Vicky

0

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

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

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

3

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

Я установил это мой исключающий RecyclerView из Transition с помощью Transition.excludeTarget(R.id.recyclerview, true);

1

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

андроида: 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); 

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^