Android RecyclerView在以下情况下崩溃;废弃或附加的视图不得回收。”;
我使用的是一个简单的Android RecyclerView在以下情况下崩溃;废弃或附加的视图不得回收。”;,android,android-recyclerview,Android,Android Recyclerview,我使用的是一个简单的RecyclerView实现,该实现来自Android网站,使用的是StaggedGridLayoutManager,我不断收到这个错误,导致我的应用程序崩溃: java.lang.IllegalArgumentException: Scrapped or attached views may not be recycled. isScrap:false isAttached:true at android.support.v7.widget.Recy
RecyclerView实现,该实现来自Android网站,使用的是StaggedGridLayoutManager
,我不断收到这个错误,导致我的应用程序崩溃:
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
s,所以我不会麻烦重新发布我的代码
还有谁知道如何处理这个错误吗?如果XML中的android:animateLayoutChanges
设置为true,并且在Java代码中调用RecyclerView的适配器上的notifyDataSetChanged()
,就会导致这个错误
因此,请避免在RecyclerViews中使用android:animateLayoutChanges
。我也必须处理此崩溃,在我的情况下,它与android:animateLayoutChanges
无关
我们正在构建的RecyclerView
中有多种类型的视图,有些视图中有EditText
s。过了一段时间,我们把这个问题归结为与焦点相关。此错误发生在回收EditText
s时,其中一个错误已被关注
当然,当新数据绑定到回收视图时,我们尝试清除焦点,但直到
android:focusableInTouchMode=“true”
设置为RecycleView
时,这才起作用。实际上,这是最终解决此问题所需的唯一更改。发生在我身上的一个特殊情况是,我在适配器中有一个视图成员,我懒得实例化一个视图,而不需要使用循环视图
这也违反了循环视图原则,在本例中,循环视图原则是存储对视图的引用。下面我举一个简单的例子:
// 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
当我在
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);
}
这修复了这个错误。在使用slimfit sticky Header时,我遇到了这个错误。这是由于设置错误的第一个位置造成的。我得到了答案
只需确保您为mSectionFirstPosition传递了正确的值我从layout属性中删除了
android:animateLayoutChanges
,问题已经解决。我使用com.squareup.picasso.RequestCreator
public void into(android.widget.ImageView target,
Callback callback)
从Internet下载图片后动态调整ImageView的大小,并保存已调整大小的宽度和高度以保留视图大小。我之所以出现此异常,是因为我将LayoutParams
保存在Map
中,并在onBindViewHolder中检索它并直接将其设置为我的ImageView
。我通过使用ImmutablePair
来修复这个问题,只存储ImageView的大小,而不是许多其他状态,并使用下面的代码来恢复它
ViewGroup.LayoutParams params = image.getLayoutParams();
params.width = widthAndHeight.getLeft();
params.height = widthAndHeight.getRight();
image.setLayoutParams(params);
请允许我为此类问题添加另一个可能的解决方案。我在
RecyclerView
中遇到了与库中粘性标题相同的问题。我使用MatrixCursor
将数据设置为recycleServiceWCursorAdapter
。出现此问题的原因是,对于所有标题,ID列等于0
。希望这能帮助某人节省几天的调试时间。对于我来说,在更高级别的视图组上进行LayoutTransition会导致相同的错误。我今天早上遇到了这个问题,但我面临的原因与上面提到的不同
通过调试,我发现我的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.RecycleServiceWrecycler.RecycleServiceWholderInternal()
检查我的按钮是否已有父按钮。如果我们将按钮添加到父级,它也将被分配给它的mParent
变量。/**
/**
* 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);
}
}
*通知回收商此项目是否可以回收。不是
*在设置setIsRecyclable()之前,不会将可回收物重新用于其他项目
*后来设置为true。对setIsRecyclable()的调用应始终成对(一个)
*对SetIsRecyCabe的调用(false)应始终与以后对的调用相匹配
*setIsRecyclable(true))。调用对可以嵌套,因为状态是内部的
*参考计数。
*
*@param recyclable此项目是否可回收。默认值
*这是真的。
*
*@see#isRecyclable()
*/
公共最终作废集可回收(布尔可回收){
可回收错误计数=可回收?可回收错误计数-1:可回收错误计数+1;
如果(误回收计数<0){
可回收错误计数=0;
如果(调试){
抛出新的运行时异常(“isRecyclable递减到0以下:”+
“无与伦比的一对刚毛
/**
* 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);
}
}
setHasStableIds(true);
@Override
public long getItemId(int position) {
return position;
}
View itemView = mRecyclerView.getLayoutManager().findViewByPosition(position);
if (itemView != null && itemView.getParent() != null) {
((ViewGroup) itemView.getParent()).removeView(itemView);
}
notifyItemRemoved(position);
nameLP = new LinearLayout.LayoutParams(context.getResources().getDisplayMetrics().widthPixels, LinearLayout.LayoutParams.WRAP_CONTENT);
nameLP2 = new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT);
Transition.excludeChildren(yourRecyclerView, true)
Transition.excludeTarget(yourRecyclerView, true)