web-dev-qa-db-de.com

RecyclerView: Wie werden zwischengespeicherte/recycelte Ansichten gelöscht?

Ich verwende eine RecyclerView, um eine Liste von Elementen mit einem Listenlayout anzuzeigen. Ich wechsle von einem Listenlayout zu einem Rasterlayout und zeige im Rasterlayout nur eine Teilmenge aller Daten. Diese Option verwendet ein anderes XML-Layout als das Listenlayout. 

All dies funktioniert gut, mit der Ausnahme, dass beim Scrollen wiederkehrende (zwischengespeicherte) Listenlayoutansichten das Raster ausfüllen, die mit den richtigen Rasterlayoutelementen gemischt werden. Mit anderen Worten, anstatt meinen layout_grid.xml für das Layout jedes Elements in der RecyclerView zu verwenden, erhalte ich Elemente mit dem layout_list.xml-Layout, jedoch in einem Rasterformat.

Dies weist darauf hin, dass der LayoutManager ordnungsgemäß funktioniert und von einer Liste zum Rasterlayout wechselt. Es werden jedoch nicht alle Elemente der Elementansicht mit dem Raster-XML-Layout neu erstellt, sondern es werden wiederverwendete Listenlayoutansichten verwendet.

Ich habe versucht RecyclerView.removeAllViews(), RecyclerView.removeAllViewInLayout(), RecyclerView.swapAdapter() (um das erneute Laden des Adapters zu erzwingen), alles ohne Erfolg.

Update:

Wenn ich zwei Positionen in der Liste nach unten scrolle und dann von Liste zu Raster wechsle, werden die ersten beiden Positionen nicht durch onCreateViewHolder (), sondern direkt in onBindViewHolder () durchlaufen und müssen daher nicht die Grid-Layout-XML verwenden. Stattdessen werden diese ersten beiden Positionselemente (glaube ich) recycelt und in ihrem Listenlayoutformat angezeigt.

21
mraviator

Ok, jetzt verstehe ich. Sie verwenden beide Layouts? Es gibt eine Methode, um den Ansichtstyp für ein Listen-/Rasterelement (ID/Position) zurückzugeben. Sie haben diese Methode auch korrekt implementiert, damit der Adapter das korrekte Layout für die neue Ansicht wiederverwenden kann. Verstehst du was ich meine? :)

5
Mann

Benutzen

recyclerView.getRecycledViewPool().clear();
18
Oleg Kovalyk

Ich hatte das gleiche Problem. Die von Mann vorgeschlagene Lösung funktioniert gut. Eine andere Option wäre, das RecycledViewPool der RecyclerView auf eine neue Instanz zu setzen. Das funktioniert auch für mich.

recyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool());

Aber ich denke, das Überschreiben von getItemViewType () ist die sauberere Lösung.

7
goflo

Es scheint, als wäre die akzeptierte Antwort die richtige für Ihren Fall. Das Zurückgeben eines anderen viewType ist wahrscheinlich das, was Sie tun mussten.

Wenn jemand einen Weg finden muss, um zwischengespeicherte Ansichtshalter zu löschen, und in diesem Thread gelandet ist, habe ich Folgendes gefunden.

Sie müssen setLayoutManager(null) und setAdapter(null) aufrufen. Wenn Sie Ihren Adapter behalten möchten, können Sie Folgendes tun: adapter = getAdapter(); setAdapter(null); setAdapter(adapter);

5
cottonBallPaws

Der Schlüssel war hier, getItemViewType(int position) zu überschreiben und so einzurichten, dass ich überprüfen konnte, mit welchem ​​Ansichtstyp (Liste oder Gitter) ich mich für diese Position beschäftige, und dann die entsprechende Sichtbehandlung für diese Position in onbindViewHolder() festlegte. Unten ist viewFormat einfach ein int, das ich auf list oder grid gesetzt habe, wenn der Benutzer auf die Menüschaltfläche tippt, um das Format zu ändern.

@Override
    public int getItemViewType(int position) {
        if (listData.size() == 0) {
            return EMPTY_VIEW;
        } else if (viewFormat == Constants.LIST_FORMATTED) {
            return Constants.LIST_FORMATTED;
        } else if (viewFormat == Constants.GRID_CONDITION) {
            return Constants.GRID_CONDITION;
        }
        return super.getItemViewType(position);
    }

Ein Benutzer, der Kommentare zu meinem ursprünglichen Beitrag gepostet hat, hat mich darauf aufmerksam gemacht, aber diese Kommentare wurden leider herausgeschnitten. Ich danke diesem Benutzer dafür, dass er mich in die richtige Richtung weist. 

3
mraviator

Recyclerview hat das Caching von Ansichten sowie den Pool mit recycelten Ansichten (View Holders Pool).

Der Cache besteht aus Ansichten (Ansichten mit aufgefüllten Daten). Wenn LayoutManager dem Recycler mitteilt, dass die Ansicht nicht mehr sichtbar ist und nicht mehr benötigt wird, überprüft RecyclerView, ob diese Ansicht für eine bestimmte Position noch gültig ist. Wenn sie gültig ist, wird sie dem Cache hinzugefügt. Wenn LM das nächste Mal die Ansicht für diese Position anfordert, wird sie zurückgegeben aus dem Cache, wie es ist.

Was ist dann recycelter Pool? Wenn Ansichten aus dem Cache entfernt werden oder keine gültigen Ansichten mehr sind, werden die auf diese Ansichten bezogenen Daten gelöscht und nur das Objekt des Ansichtshalters im Pool gehalten. Je nach itemType kann der Pool Ansichtsinhaber verschiedener Elementtypen haben.

In Ihrem Fall sind Ihre Ansichten für diese bestimmte Position nicht gültig, da Sie eine völlig andere Ansicht anzeigen möchten. Ihr Adapter sollte dem Recycler mitteilen, dass alle Ansichten ungültig sind. Sie können notifyDataSetChanged für alle Elemente verwenden. Recyclerview entfernt Ansichten aus dem Cache-Speicher und fügt diese dem Recyler-Ansichtspool hinzu. Wenn LM nun nach einer Ansicht fragt, wird entweder die wiederverwendete Ansicht (nach itemType) oder die neu erstellte Ansicht zurückgegeben, und der Adapter bindet Daten an diese Ansichten.

0
Virat18
final int targetCacheSize = 2;
    recyclerView.setItemViewCacheSize(Integer.MIN_VALUE);
    recyclerView.getRecycledViewPool().clear();
    recyclerView.setItemViewCacheSize(targetCacheSize);
0
李海标

Mach das einfach Einfach !!

adapter.notifyItemRangeRemoved(0,adapter.getItemCount());

  adapter.notifyItemRangeRemoved(0,adapter.getItemCount());
                   for (int i = 0; i < array.length(); i++) {
                        JSONObject object = array.getJSONObject(i);
                         ////
                        data_List.add(data);
                    }
0
Shahjad S