RecyclerView는 "스크래핑되거나 연결된 뷰가 재활용되지 않을 수 있습니다."
a를 사용 RecyclerView
하여 Android 웹 사이트에서 가져온 간단한 구현을 사용하고 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)
간단히 말해서 말 그대로 웹 사이트의이 페이지에서 가져온 것과 동일한 구현이라는 것을 의미합니다 . 유일한 차이점은 내 그리드 항목의 레이아웃이 s ImageView
와 TextView
s라는 것이므로 코드를 다시 게시하지 않아도됩니다.
이 오류가 발생하고 처리 방법을 아는 사람이 있습니까?
이 오류는 XML android:animateLayoutChanges
에서 true로 설정 notifyDataSetChanged()
하고 Java 코드에서 RecyclerView의 어댑터 를 호출하면 발생 합니다.
따라서 android:animateLayoutChanges
RecyclerViews와 함께 사용하지 마십시오 .
나는 또한이 충돌을 처리해야했으며 내 경우에는 android:animateLayoutChanges
.
RecyclerView
그것은 일부의 견해 우리가 가진 건물 한 종류 이상 가지고 있었다 EditText
그들들. 잠시 후 우리는 초점과 관련된 문제를 고정했습니다. 이 버그는 EditText
s 를 재활용하는 동안 발생하며 그중 하나가 집중됩니다.
당연히 우리는 새 데이터가 재활용 된 뷰에 바인딩 될 때 초점을 지우려고 시도했지만 android:focusableInTouchMode="true"
이 설정 될 때까지 작동하지 않았습니다 RecycleView
. 사실 이것이이 문제가 사라지기 위해 결국 필요한 유일한 변화입니다.
android:animateLayoutChanges
레이아웃 속성에서 제거 하고 문제가 해결되었습니다.
누구나이 문제에 직면 할 수있는 이유 중 특성 android:animateLayoutChanges="true"
을 RecyclerView로 설정했는지 확인하세요 . 이로 인해 RecyclerView의 항목이 재활용되고 다시 연결되지 않습니다. 이를 제거하고 LinearLayout / RelativeLayout과 같은 RecyclerView의 부모 컨테이너에 속성을 할당하면 문제가 해결되는 것을 볼 수 있습니다.
이틀이 걸렸지 만이 문제를 해결할 수 없었습니다. 결국 항목 프리 페치를 비활성화해야했습니다.
레이아웃 관리자를 설정할 때 간단히 호출 할 수 있습니다.
mGridLayoutManager.setItemPrefetchEnabled(false);
그것은 나를 위해 오류를 제거했습니다. 누군가에게 유용하기를 바랍니다.
슬림핏 고정 헤더를 사용하는 동안이 오류가 발생했습니다. 첫 번째 위치를 잘못 설정했기 때문입니다. 나는 여기 에 답을 얻었다
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에 올바른 값을 전달하고 있는지 확인하십시오.
오늘 아침이 문제를 만났지만 위에서 언급 한 것과 같은 이유에 직면하지 않았습니다.
디버그를 통해 내 ViewHolder의 항목 뷰가 가지고 mParent
있고 null이 아니라는 것을 발견했습니다. 정상적인 경우에는 없음이어야합니다 (로그에서 "첨부 된 뷰는 재활용되지 않을 수 있습니다"라고 말하는 것입니다). 자식 뷰가 이미 부모에 연결되어 있으면 재활용 할 때 실패가 발생할 수 있습니다.)
하지만 매번 수동으로 자식 뷰를 첨부하지 않았습니다. 그리고 내 ViewHolder에서 자식 뷰를 확장하려고 할 때 다음과 같이 완료되었음을 알았습니다.
layoutInflater.inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
마지막 매개 변수 attachToRoot
는 거짓이어야합니다.
으로 변경 한 후 false
문제를 해결했습니다.
그건 그렇고, 내 지원 라이브러리를 최신 버전 25.0.0으로 업그레이드 할 때만이 충돌이 발생한 것을 볼 수 있습니다. 버전 23.4.0을 사용하기 전에는이 문제가 발생하지 않습니다. 최신 지원 라이브러리에서 변경된 것이있을 것 같습니다.
이 도움을 바랍니다.
스크롤 할 때도 같은 오류가 발생했습니다 RecyclerView
: animateLayoutChanges="true"
레이아웃 파일에서 제거 RecyclerView
한 다음 모든 것이 작동했습니다.
제 경우 Transition
에는 소프트웨어 키보드가 표시 되려고했기 때문에 RecyclerView의 크기를 조정하려고 할 때 실행 중이 어서 발생했습니다 .
다음 Transition
을 사용하여 RecyclerView를 제외하고 수정했습니다.Transition.excludeTarget(R.id.recyclerview, true);
RecyclerView의 레이아웃 파일에 animateLayoutChanges = "true"가있을 때마다이 오류가 발생했습니다. 이 속성을 삭제하면 오류가 사라집니다!
While in my case it was removing animateOnLayoutChange
from the recyclerView that fixed the crash, I still needed the ability to animate the layout changes within the viewHolder. In order to get this to work, the LinearLayout' in the view holder needs the
animateOnLayoutChange' to to true, but I needed to notifyItemChanged
to the adapter. This then allowed both of the layoutTransition animations to kick off (for expanding and collapsing the viewHolder), and also avoids the scrapped exception. So yes, avoid putting the animateOnLayoutChange on the recylcerView and use the various notify methods to enable the default animations on view size changes.
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);
}
Function at android.support.v7.widget.RecyclerViewRecycler.recyclerViewHolderinternal()
check whether my button has already a parent or not. Which if we add button to parent, it will be also assign RecyclerView
to its mParent
variable.
There are a number of reason why this exception is called. In my case it was due to animations running thats why the views are still attached and could not be removed to the view. Only when the animation is finished thus the view could be removed and recycled.
There are two types of animation that could affect the recyclerview recycling.
1) Is the RecyclerView.ItemAnimator
- this should not be the problem. This should be pretty much safe to use as it check for attach and scrapped views and handle recycling properly.
2) android:animateLayoutChanges="true"
or TransitionManager.beginDelayedTransition()
or TransitionManager.go(), etc. - These animations runs on its own and take hold of the items to animate. This result to the views being force to be attached until the animation is finished. The recyclerview do not have any knowledge of these animations since it is outside its scope. Therefore the recyclerview
might try to recycle an item thinking it could be recycled properly but the problem is that these APIs are still holding on to the views until there animation is finished.
If you are using android:animateLayoutChanges="true"
or TransitionManager.beginDelayedTransition()
or TransitionManager.go(), etc. simply remove the RecyclerView
and its children from the animation.
You can simply do this by taking hold of the Transition
and calling
Transition.excludeChildren(yourRecyclerView, true)
Transition.excludeTarget(yourRecyclerView, true)
Note:
Take note that it is important to use Transition.excludeChildren()
to exclude all of Recyclerview
children from the animation and not just the Recyclerview
itself.
I solved this issue by calling
setHasStableIds(true);
in the adapter's constructor and overriding getItemId
in the adapter:
@Override
public long getItemId(int position) {
return position;
}
I saw this happen for me when I used a custom object in the ViewHolder
for the RecyclerView
adapter.
To fix the issue I cleared the custom object which in my case was a timer in the onViewRecycled(ViewHolder holder)
for the adapter as 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.
/**
* 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
:remove data from list.
2、notifyDataSetChanged
:notifyDataSetChanged();
3、notifyItemRemoved
:show animation.
4、notifyItemRangeChanged
:range view size and redraw the viewHolders(onBindViewHolder methods)
In my case, I used the TransitionManager.beginDelayedTransition()
before adding a view on top of the recyclerView. I removed the TransitionManager.beginDelayedTransition()
and no crash.
Remove android:animateLayoutChanges="true"
from recycleview or set android:animateLayoutChanges="false"
this exception is not cause of
android:animateLayoutChanges
or
android:focusableInTouchMode
this final correct answer is just because you set a 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);
the nameLP is OK. the nameLP2 occur the crash .bug is here.
I try all of answers of this page. trust me.
I use com.squareup.picasso.RequestCreator
public void into(android.widget.ImageView target,
Callback callback)
to dynamically resize ImageView's size after download picture from Internet, and saves the resized width and height to preserve the view size. I got this Exception because I saved LayoutParams
in a Map
, and in my onBindViewHolder, I retrieved it and directly set it to my ImageView
. I fix this by use ImmutablePair<Integer, Integer>
to only store ImageView's size rather than a lot of other states, and use following code to restore it.
ViewGroup.LayoutParams params = image.getLayoutParams();
params.width = widthAndHeight.getLeft();
params.height = widthAndHeight.getRight();
image.setLayoutParams(params);
For me the same bug with caused by a LayoutTransition on a higher level ViewGroup.
Let me add another possible fix for this kind of issue, please. I had the same problem with superSlim library for sticky headers in RecyclerView
. I used MatrixCursor
to set data to RecyclerViewCursorAdapter
. The reason for this issue was ID columns equals to 0
for all headers. Hope that would help someone to save couple days of debugging.
In my case the problem was because of the incorrect implementing of this method public long getItemId(int position)
(overrided from RecyclerView.Adapter
method).
The old code will get two different ids for the same item (in my case it is the footer item), after fixing the implementation the issue has gone.
Workaround solution if reason of Exception is what itemView has parent. In 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);
A Peculiar case which occured for me was that i had a view member in the adapter and i was lazy instantiating a view which there is no need to do with the recycle view.
It also goes against the recycle views principles which as your storing a reference to the view in this case. I give a quick example below:
// 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
I had this issue because I overwrite equals()
and hashcode()
method of ViewHolder
of RecyclerView
.ViewHolder by calculating data equality and hashcode, then the recycle logic did not work and crashed, I just remove the overwrite and fixed.
'Programming' 카테고리의 다른 글
PreferenceScreen에 버튼을 추가하는 방법 (0) | 2020.08.08 |
---|---|
Spring-Data-JPA 주석에 대한 setMaxResults? (0) | 2020.08.08 |
노드 영구 / usr / bin / env : node : 해당 파일 또는 디렉토리 없음 (0) | 2020.08.08 |
복사 생성자와 Clone () (0) | 2020.08.07 |
오프라인 개발을 위해 Maven을 어떻게 구성합니까? (0) | 2020.08.07 |