RecyclerView crashes when "recycled or attached species cannot be recycled"

I am using a simple RecyclerView implementation taken from the Android website using the StaggeredGridLayoutManager , and I keep getting this error, which causes my application to crash:

 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) 

Simple, I literally mean that the same implementation is taken from this page on their website , the only difference is that my grid layout is ImageView and a couple of TextView s, so I won't worry about code wrapping.

Does anyone else get this error and know how to handle it?

+61
android android-recyclerview
Oct 21 '14 at 1:45
source share
22 answers

This error occurs if your XML android:animateLayoutChanges set to true and you call notifyDataSetChanged() on the RecyclerView adapter in Java code.

So, just don't use android:animateLayoutChanges with RecyclerViews.

+121
Oct 21 '14 at 6:01
source share

I also had to deal with this failure, and in my case it had nothing to do with android:animateLayoutChanges .

In the RecyclerView we built, it had several kinds of views, and some of them had an EditText . After a while, we stuck the question to being connected with the focus. This error occurs when disposing of EditText , and one of them is focused.

Naturally, we tried to clear focus when the new data is tied to the redesigned view, but this did not work until android:focusableInTouchMode="true" is set to RecycleView . This is actually the only change that was needed to complete this problem.

+38
Jan 07 '15 at 9:23
source share

I removed the android:animateLayoutChanges from the layout and the problem was resolved.

+17
Jan 19 '16 at 21:21
source share

When using slimfit sticky headers, I came across this error. This was caused by an incorrect first position. I got an answer 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); } 

just make sure you pass the correct value for mSectionFirstPosition

+8
Dec 11 '15 at 7:24
source share

Among the reasons anyone may run into this problem, check to see if the android:animateLayoutChanges="true" attribute is set in RecyclerView. This will cause the RecyclerView elements to fail and reconnect. Delete it and assign the attribute to the parent RecyclerView container, for example LinearLayout / RelativeLayout, and you will see that the problem has disappeared.

+7
Mar 22 '17 at 14:37
source share

I met this problem this morning, but I am not confronted with the same reason that was mentioned above.

Through debug, I found that the view of the element in my ViewHolder has mParent , and it is not null, that in the normal case it should not be anything (that the message in the log, β€œthe attached view cannot be processed,” I think that this means that if the child view is already bound to the parent, this may cause reuse to fail.)

But I did not bind the child view manually each time. And I found that this was done when I try to inflate the kind of child in my ViewHolder, something like:

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

And the last attachToRoot parameter should be false.

After I changed it to false , I fixed my problem.

By the way, I see that this failure occurred when I upgrade my support library to the latest version 25.0.0. Before I used version 23.4.0, and I do not see this problem. I assume that something needs to be changed in the latest support library.

I hope for this help.

+5
Nov 25 '16 at 7:10
source share

I solve this problem by removing parent.addView() in onCreateViewHolder

This is my code.

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

The function in android.support.v7.widget.RecyclerViewRecycler.recyclerViewHolderinternal() checks if my button already has a parent element. What if we add the button to the parent, it will also assign RecyclerView its mParent variable.

+3
Jan 13 '17 at 19:08
source share

It took me two days, but I could not get around this, in the end, I had to turn off prefetching.

When setting up the layout manager, you can simply call

mGridLayoutManager.setItemPrefetchEnabled(false);

It made me leave. Hope this will be helpful to someone.

+2
16 Sep '17 at 10:52 on
source share

In my case, this was due to the fact that when trying to resize the RecyclerView Transition was launched, because the software keyboard was about to show.

I fixed it by excluding RecyclerView from Transition using Transition.excludeTarget(R.id.recyclerview, true);

+2
Nov 29 '17 at 22:39
source share

I saw this happen to me when I used a custom object in the ViewHolder for the RecyclerView adapter.

To fix the problem, I cleared the user object, which in my case was a timer in the onViewRecycled(ViewHolder holder) for the adapter, as shown below:

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

This fixed the bug.

+1
04 Sep '15 at 6:28
source share
  /** * 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
Mar 03 '17 at 5:58 on
source share

1, remove : remove data from the list.

2, notifyDataSetChanged : notifyDataSetChanged ();

3, notifyItemRemoved : show animation.

4, notifyItemRangeChanged : range size and redraw viewHolders(onBindViewHolder methods)

+1
Mar 03 '17 at 6:08
source share

I solved this problem by calling

 setHasStableIds(true); 

in the adapter constructor and overriding getItemId in the adapter:

 @Override public long getItemId(int position) { return position; } 
+1
Jun 15 '17 at 21:29
source share

this exception is not the cause

android: animateLayoutChanges

or

Android: focusableInTouchMode

this final correct answer is only that you install 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 name is ok. LP2 name crashes .bug here.

I try all the answers on this page. believe me.

+1
Dec 16 '17 at 3:19 on
source share

A special case that arose for me was that I had a view member in the adapter, and I was lazy, creating a view that does not need to be done with viewing digging.

It also contradicts the principles of transcoding, which in this case retain a reference to the submission. The following is a brief example:

 // 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 
0
Feb 20 '15 at 15:58
source share

I am using com.squareup.picasso.RequestCreator

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

to dynamically resize the ImageView after downloading the image from the Internet and save the changed width and height to preserve the size of the view. I got this exception because I saved LayoutParams in Map , and in my onBindViewHolder I got it and set it directly to ImageView . I will fix this using ImmutablePair<Integer, Integer> to store only the size of the ImageView and not many other states, and use the following code to restore it.

 ViewGroup.LayoutParams params = image.getLayoutParams(); params.width = widthAndHeight.getLeft(); params.height = widthAndHeight.getRight(); image.setLayoutParams(params); 
0
Jan 21 '16 at 5:21
source share

Let me add another possible solution for this kind of questions, please. I had the same problem with the superSlim library for sticky headers in RecyclerView . I used MatrixCursor to set the data on the RecyclerViewCursorAdapter . The cause of this problem was ID columns equal to 0 for all headers. Hope this helps someone save a couple of days of debugging.

0
Mar 15 '16 at 2:37
source share

For me, the same error caused by LayoutTransition at a higher ViewGroup level.

0
Aug 05 '16 at 12:33
source share

In my case, the problem was due to the incorrect implementation of this method public long getItemId(int position) (overridden from the RecyclerView.Adapter method).

The old code will receive two different identifiers for the same element (in my case, this is a footer element), after fixing the implementation, the problem disappeared.

0
Mar 09 '17 at 14:16
source share

In my case, I used TransitionManager.beginDelayedTransition() before adding the view on top of the recyclerView. I deleted TransitionManager.beginDelayedTransition() and without fail.

0
May 31 '17 at 1:56 a.m.
source share

A workaround if the reason for the exception is that itemView has a parent element. In the code where you have notifyItemRemoved (position), remove itemView from RecyclerView:

 View itemView = mRecyclerView.getLayoutManager().findViewByPosition(position); if (itemView != null && itemView.getParent() != null) { ((ViewGroup) itemView.getParent()).removeView(itemView); } notifyItemRemoved(position); 
0
Sep 25 '17 at 8:50
source share

Remove android:animateLayoutChanges="true" from recycleview or set android:animateLayoutChanges="false"

0
Oct 11 '17 at 10:15 on
source share



All Articles