RecyclerView崩溃时,“报废或附加的意见可能无法回收”

我正在使用StaggeredGridLayoutManager从Android网站采取一个简单的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) 

简单地说,我的意思是说,这是从他们的网站上的这个页面采取的相同的实现,唯一的区别是我的网格项目的布局是一个ImageView和几个TextView ,所以我不会打扰重新发布我的代码。

任何人得到这个错误,并知道如何处理它?

如果在您的XML android:animateLayoutChanges设置为true,并且您在Java代码中的RecyclerView适配器上调用notifyDataSetChanged() ,则会导致此错误。

所以,只要避免使用android:animateLayoutChanges与RecyclerViews。

我不得不处理这个崩溃,在我的情况下,它与android:animateLayoutChanges没有任何android:animateLayoutChanges

我们正在构build的RecyclerView有不止一种types的视图,其中一些有EditText 。 过了一会儿,我们把这个问题固定在焦点上。 这个错误发生在回收EditText ,其中一个焦点。

当然,我们尝试清除新的数据被绑定到一个循环视图的焦点,但是这并不工作,直到在RecycleView上设置了android:focusableInTouchMode="true" RecycleView android:focusableInTouchMode="true" 。 其实这是这个问题最终需要消除的唯一改变。

我从布局属性中删除了android:animateLayoutChanges ,问题已经解决。

当使用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的正确值

任何人都可以面对这个问题的原因之一,检查你是否已经设置属性android:animateLayoutChanges="true"到RecyclerView。 这将导致回收和重新附加RecyclerView的项目失败。 删除它,并将属性分配给RecyclerView的父容器,如LinearLayout / RelativeLayout,你应该看到问题消失。

今天早上我遇到了这个问题,但是我没有面对上面提到的同样的原因。

通过debugging,我发现我的ViewHolder中的项目视图有mParent ,它不是空的,在正常情况下,它应该是没有的(这就是日志说,“附加视图可能无法回收”,我认为这意味着,如果孩子查看已经附加到父母,这将是一些如何导致回收时失败。)

但是我没有每次手动附加子视图。 我发现,当我尝试膨胀我的ViewHolder中的子视图时,这是完成的,如下所示:

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

最后一个参数attachToRoot应该是false。

在我将其更改为false ,我解决了我的问题。

顺便说一句,我只看到这个崩溃发生时,我升级我的支持库到最新版本25.0.0。 在我使用版本23.4.0之前,我没有看到这个问题的发生。 我想在最新的支持库中应该改变一些东西。

希望这个帮助。

我通过删除onCreateViewHolder parent.addView()来解决这个问题

这是我的代码

 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()函数检查我的button是否已经是父母或不。 如果我们将button添加到父项,那么也会将RecyclerView分配给它的mParentvariables。

当我在RecyclerView适配器的ViewHolder使用自定义对象时,我看到了这种情况。

为了解决这个问题,我清除了自定义对象,在我的情况是一个计时器在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 :显示animation。

4, notifyItemRangeChanged :范围视图大小并重绘viewHolders(onBindViewHolder methods)

我通过调用来解决这个问题

 setHasStableIds(true); 

在适配器的构造函数中,并在适配器中重写getItemId

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

我使用com.squareup.picasso.RequestCreator

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

从Internet下载图片后dynamic调整ImageView的大小,并保存调整后的宽度和高度以保留视图大小。 我得到这个exception,因为我保存在Map LayoutParams ,并在我的onBindViewHolder,我检索它,并直接将其设置为我的ImageView 。 我通过使用ImmutablePair<Integer, Integer>来解决这个问题,只存储ImageView的大小,而不是很多其他的状态,并使用下面的代码来恢复它。

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

对于我来说,由更高级ViewGroup上的LayoutTransition引起的同样的错误。

请为此类问题添加另一个可能的修复方法。 我在RecyclerView遇到了与superSlim库中的粘性头相同的问题。 我使用MatrixCursor将数据设置为RecyclerViewCursorAdapter 。 这个问题的原因是所有头的ID列等于0 。 希望能帮助别人节省几天的debugging时间。

在我的情况下,这个问题是由于这个方法public long getItemId(int position) (从RecyclerView.Adapter方法重写public long getItemId(int position)的不正确的实现。

旧的代码将得到两个不同的ID为同一项目(在我的情况下,它是页脚项目),修复实施后,问题已经消失。

在我的情况下,我使用了TransitionManager.beginDelayedTransition()然后在recyclerView顶部添加视图。 我删除了TransitionManager.beginDelayedTransition()并没有崩溃。

这花了我两天,但无法绕过这个,最后,我不得不禁用项目预取。

设置布局pipe理器时,您可以直接调用

mGridLayoutManager.setItemPrefetchEnabled(false);

这让我的错误消失了。 希望对某人有用。

如果Exception的原因是itemView有父项的解决方法。 在代码中,你有notifyItemRemoved(位置),从RecyclerView中删除itemView:

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

android:animateLayoutChanges="true"删除android:animateLayoutChanges="true" ,或设置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