Używam prostej implementacji RecyclerView
pobranej z witryny Android przy użyciu a StaggeredGridLayoutManager
i ciągle otrzymuję ten błąd, który powoduje awarię mojej aplikacji:
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)
Mówiąc prościej, dosłownie mam na myśli tę samą implementację wziętą z tej strony w ich witrynie internetowej , jedyną różnicą jest to, że układ mojego elementu siatki to ImageView
i kilka TextView
s, więc nie będę zawracać sobie głowy ponownym publikowaniem kodu.
Czy ktoś jeszcze otrzymuje ten błąd i wie, jak sobie z nim radzić?
android
android-recyclerview
StackOverflowMaster
źródło
źródło
Odpowiedzi:
Ten błąd jest spowodowany, jeśli w kodzie XML
android:animateLayoutChanges
ustawiono wartość true i wywołujesznotifyDataSetChanged()
adapter RecyclerView w kodzie Java.Dlatego po prostu unikaj używania
android:animateLayoutChanges
z RecyclerViews.źródło
RecyclerView
używaDefaultItemAnimator
domyślnie.Miałem też do czynienia z tą awarią iw moim przypadku nie miało to nic wspólnego
android:animateLayoutChanges
.RecyclerView
My budulcowe miał więcej niż jeden typ poglądów w nim i niektóre były uwzględniającEditText
sw nich. Po chwili przypięliśmy ten problem do fokusu. Ten błąd występuje podczas recyklinguEditText
s, a jeden z nich jest skupiony.Oczywiście próbowaliśmy wyczyścić fokus, gdy nowe dane są wiązane z odtworzonym widokiem, ale to nie zadziałało, dopóki nie
android:focusableInTouchMode="true"
zostanie włączoneRecycleView
. Właściwie to jedyna zmiana, która była potrzebna w końcu, aby ten problem zniknął.źródło
android:focusableInTouchMode="true"
ponieważ zdarza się to tylko czasami na niektórych urządzeniach (rzadko) i domyślam się, że nie ma to związku z moim problemem, ale śledzenie stosu dla awarii jest prawie takie samo.android:focusableInTouchMode="true"
wcale mi nie pomogło. Więc wyczyściłem fokus wonViewDetachedFromWindow
oddzwonieniu.public void onViewDetachedFromWindow(@NonNull RecyclerView.ViewHolder holder) { if (holder instanceof ItemViewHolder) { ItemViewHolder item = (ItemViewHolder) holder; if (item.editText.isFocused()) item.editText.clearFocus(); } }
Usunąłem właściwość
android:animateLayoutChanges
z układu i problem został rozwiązany.źródło
android:animateLayoutChanges
na moim RV.Wśród powodów, dla których każdy może napotkać ten problem, sprawdź, czy ustawiłeś atrybut
android:animateLayoutChanges="true"
na RecyclerView. Spowoduje to niepowodzenie recyklingu i ponownego dołączania elementów RecyclerView. Usuń go i przypisz atrybut do kontenera nadrzędnego RecyclerView, takiego jak LinearLayout / RelativeLayout, a problem powinien zniknąć.źródło
Zajęło mi to dwa dni, ale nie mogłem tego obejść, w końcu musiałem wyłączyć wstępne pobieranie elementów.
Podczas ustawiania menedżera układu możesz po prostu zadzwonić
mGridLayoutManager.setItemPrefetchEnabled(false);
To sprawiło, że błąd zniknął dla mnie. Mam nadzieję, że komuś się przyda.
źródło
Podczas korzystania z lepkich nagłówków slimfit napotkałem ten błąd. Było to spowodowane niewłaściwym ustawieniem pierwszej pozycji. Mam tutaj odpowiedź
po prostu upewnij się, że przekazujesz poprawną wartość mSectionFirstPosition
źródło
item
tu jestSpotkałem się z tym problemem dziś rano, ale nie mam tego samego powodu, co wspomniano powyżej.
Podczas debugowania stwierdziłem, że widok elementu w moim ViewHolder ma
mParent
i nie jest zerowy, co w normalnym przypadku powinno być brakiem (tak mówi dziennik: „dołączony widok nie może zostać ponownie przetworzony”, myślę, że oznacza to, że jeśli widok podrzędny jest już przywiązany do rodzica, spowodowałoby to niepowodzenie podczas recyklingu).Ale nie za każdym razem ręcznie załączałem widok dziecka. I stwierdziłem, że jest to zrobione, gdy próbuję zawyżać widok dziecka w moim ViewHolder, na przykład:
Ostatni parametr
attachToRoot
powinien być fałszywy.Po zmianie na
false
rozwiązałem problem.Nawiasem mówiąc, ta awaria wystąpiła tylko wtedy, gdy zaktualizuję bibliotekę pomocy technicznej do najnowszej wersji 25.0.0. Wcześniej używałem wersji 23.4.0 i nie widzę tego problemu. Myślę, że w najnowszej bibliotece wsparcia powinno coś się zmienić.
Mam nadzieję, że to pomoże.
źródło
Napotkałem również ten sam błąd podczas przewijania
RecyclerView
: potem usunąłemanimateLayoutChanges="true"
plik układu,RecyclerView
a potem wszystko działało.źródło
W moim przypadku stało się tak, ponieważ miałem
Transition
uruchomiony podczas próby zmiany rozmiaru RecyclerView, ponieważ klawiatura oprogramowania miała się wyświetlić.Naprawiłem to wykluczając RecyclerView z
Transition
przy użyciuTransition.excludeTarget(R.id.recyclerview, true);
źródło
Istnieje wiele powodów, dla których wywoływany jest ten wyjątek. W moim przypadku było to spowodowane uruchomieniem animacji, przez co widoki są nadal dołączone i nie można ich było usunąć z widoku. Dopiero po zakończeniu animacji widok można było usunąć i ponownie wykorzystać.
Istnieją dwa rodzaje animacji, które mogą wpływać na recykling w widoku recyklingu.
1) Czy
RecyclerView.ItemAnimator
- to nie powinno być problemem. Powinno to być całkiem bezpieczne w użyciu, ponieważ sprawdza załączone i złomowane widoki oraz prawidłowo obsługuje recykling.2)
android:animateLayoutChanges="true"
lubTransitionManager.beginDelayedTransition()
lub TransitionManager.go (), itd. - Te animacje działają samodzielnie i przejmują elementy do animacji. Powoduje to wymuszenie dołączania widoków do zakończenia animacji. Widok recyklingu nie ma żadnej wiedzy o tych animacjach, ponieważ znajduje się poza jego zakresem. W związku z tymrecyclerview
mogą próbować przetworzyć element, myśląc, że można go prawidłowo poddać recyklingowi, ale problem polega na tym, że te interfejsy API nadal zachowują widoki, dopóki animacja nie zostanie zakończona.Jeśli używasz
android:animateLayoutChanges="true"
lubTransitionManager.beginDelayedTransition()
lub TransitionManager.go () itp., Po prostu usuńRecyclerView
i jego elementy podrzędne z animacji.Możesz to po prostu zrobić, chwytając
Transition
i dzwoniącUwaga:
Zwróć uwagę, że ważne jest,
Transition.excludeChildren()
aby wykluczyć wszystkieRecyclerview
dzieci z animacji, a nie tylkoRecyclerview
samą.źródło
Transition.excludeChildren
. Tworzysz instancję obiektu przejścia, takiego jakval transition = AutoTransition()
:, wywołajexcludeChildren(recyclerView, true)
ten obiekt i przekaż go dobeginDelayedTransaction() as the second parameter
.Ja również otrzymywałem ten błąd za każdym razem, gdy miałem animateLayoutChanges = "true" w pliku układu dla RecyclerView. Usuń ten atrybut, a błąd zniknie!
źródło
Podczas gdy w moim przypadku było to usuwanie
animateOnLayoutChange
z recyklinguView, które naprawiło awarię, nadal potrzebowałem możliwości animowania zmian układu w ramach elementu viewHolder. Aby to zadziałało,LinearLayout' in the view holder needs the
animateOnLayoutChange 'to true, ale potrzebowałemnotifyItemChanged
adaptera. Pozwoliło to na uruchomienie obu animacji layoutTransition (w celu rozwijania i zwinięcia elementu viewHolder), a także uniknięcie odrzuconego wyjątku. Więc tak, unikaj umieszczania animateOnLayoutChange w recylcerView i używaj różnych metod powiadamiania, aby włączyć domyślne animacje przy zmianach rozmiaru widoku.źródło
Rozwiązuję ten problem, usuwając
parent.addView()
wonCreateViewHolder
To jest mój kod
Funkcja przy
android.support.v7.widget.RecyclerViewRecycler.recyclerViewHolderinternal()
sprawdzaniu, czy mój przycisk ma już rodzica, czy nie. Który jeśli dodamy przycisk do rodzica, zostanie on również przypisanyRecyclerView
do jegomParent
zmiennej.źródło
Widziałem to się stało dla mnie, kiedy stosowane niestandardowego obiektu w
ViewHolder
naRecyclerView
adapterze.Aby rozwiązać problem, wyczyściłem niestandardowy obiekt, który w moim przypadku był zegarem w
onViewRecycled(ViewHolder holder)
adapterze, jak poniżej:To naprawiło błąd.
źródło
źródło
1 、
remove
: usuń dane z listy.2 、
notifyDataSetChanged
: notifyDataSetChanged ();3,
notifyItemRemoved
animacja pokazu.4
notifyItemRangeChanged
: Zakres rozmiarów widok i przerysowanieviewHolders(onBindViewHolder methods)
źródło
notifyItemRemoved
podczas usuwaniafooter
i awarii aplikacji, zmień tonotifyDataSetChanged
i teraz działa dobrze. dziękujęW moim przypadku użyłem
TransitionManager.beginDelayedTransition()
przed dodaniem widoku na wierzchu recyclinglerView. UsunąłemTransitionManager.beginDelayedTransition()
i bez awarii.źródło
Rozwiązałem ten problem dzwoniąc
w konstruktorze adaptera i nadpisywanie
getItemId
w adapterze:źródło
Usuń
android:animateLayoutChanges="true"
z widoku do recyklingu lub zestawuandroid:animateLayoutChanges="false"
źródło
używam
com.squareup.picasso.RequestCreator
aby dynamicznie zmienić rozmiar ImageView po pobraniu obrazu z Internetu i zapisać zmienioną szerokość i wysokość, aby zachować rozmiar widoku. Otrzymałem ten wyjątek, ponieważ zapisałem
LayoutParams
w aMap
, aw moim onBindViewHolder pobrałem go i bezpośrednio ustawiłem na plikImageView
. Naprawiłem to, używającImmutablePair<Integer, Integer>
tylko do przechowywania rozmiaru ImageView, a nie wielu innych stanów, i używam następującego kodu, aby go przywrócić.źródło
Dla mnie ten sam błąd spowodowany przez LayoutTransition na wyższym poziomie ViewGroup.
źródło
Dodam jeszcze jedną możliwą poprawkę tego rodzaju problemu. Miałem ten sam problem z biblioteką superSlim dla lepkich nagłówków
RecyclerView
. KiedyśMatrixCursor
ustawiałem dane naRecyclerViewCursorAdapter
. Przyczyną tego problemu było to, że kolumny ID są równe0
dla wszystkich nagłówków. Mam nadzieję, że to pomoże komuś zaoszczędzić kilka dni na debugowaniu.źródło
W moim przypadku problem wynikał z nieprawidłowej implementacji tej metody
public long getItemId(int position)
(nadpisana zRecyclerView.Adapter
metody).Stary kod otrzyma dwa różne identyfikatory dla tej samej pozycji (w moim przypadku jest to pozycja stopki), po naprawieniu implementacji problem zniknął.
źródło
Rozwiązanie obejścia, jeśli przyczyną wyjątku jest element nadrzędny itemView. W kodzie, w którym masz notifyItemRemoved (pozycja), usuń itemView z RecyclerView:
źródło
Osobliwy przypadek, który wystąpił u mnie, polegał na tym, że miałem element widoku w adapterze i leniwie tworzyłem wystąpienie widoku, którego nie ma potrzeby robić z widokiem odtwarzania.
Jest to również sprzeczne z zasadami recyklingu poglądów, które przechowują odniesienie do widoku w tym przypadku. Poniżej podaję szybki przykład:
źródło
ten wyjątek nie jest przyczyną
lub
ta ostatnia prawidłowa odpowiedź jest taka, że ustawiłeś WRONG LayoutParams .
nazwaLP jest OK. nazwaLP2 występuje awaria. błąd jest tutaj.
Próbuję wszystkich odpowiedzi na tej stronie. Zaufaj mi.
źródło
Miałem ten problem, bo nadpisać
equals()
ihashcode()
metodaViewHolder
zRecyclerView
.ViewHolder obliczając równości danych i hashcode, wtedy logika recyklingu nie działa i rozbił się, po prostu usunąć nadpisywania i stałe.źródło