it-swarm.com.de

Gute Lösung, um Listenansichtselemente beizubehalten, wenn Benutzer das Telefon drehen und alle Daten in ArrayAdapter behalten

Ich verwende Fragment mit ListView. Ich fülle den mit dieser Listenansicht verknüpften ArrayAdapter mit Daten, die im benutzerdefinierten Loader (aus dem Internet) empfangen wurden. Der benutzerdefinierte ArrayAdapter unterstützt das unendliche Scrollen (Paging).

Was ist die beste Methode, um Elemente in ArrayAdapter zu speichern, wenn der Benutzer das Gerät dreht und die Bildlaufposition in ListView beibehält?

Ich denke an die Erstellung eines nicht-visuellen Fragments mit ArrayAdapter und die Verwendung der setRetainInstance-Methode zum Speichern von Werten.

Irgendwelche Vorschläge für eine bessere Lösung?

41
barbarian

Um mit dem Android Framework und dem Fragment-Lebenszyklus zu arbeiten, sollten Sie die onSaveInstanceState -Methode in Ihrem Fragment implementieren. Der Einfachheit halber habe ich angenommen, dass Sie ein Array von String-Werten haben, die Sie können get to (ich erweitere ArrayAdapter im Allgemeinen, um die Ansichtskonstruktion zu kapseln und eine bequeme Methode für den Zugriff auf das gesamte zugrunde liegende Dataset bereitzustellen):

public void onSaveInstanceState(Bundle savedState) {

    super.onSaveInstanceState(savedState);

    // Note: getValues() is a method in your ArrayAdapter subclass
    String[] values = mAdapter.getValues(); 
    savedState.putStringArray("myKey", values);

}

Sie können dann die Daten in Ihrer onCreate-Methode (oder onCreateView oder onActivityCreated - siehe das Fragment JavaDoc ) wie folgt abrufen:

public void onCreate (Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    if (savedInstanceState != null) {
        String[] values = savedInstanceState.getStringArray("myKey");
        if (values != null) {
           mAdapter = new MyAdapter(values);
        }
    }

    ...

}

Auf diese Weise wird sichergestellt, dass alle Lebenszyklusereignisse ordnungsgemäß behandelt werden, ohne dass Daten verloren gehen, einschließlich der Gerätedrehung und des Wechsels des Benutzers zu anderen Anwendungen. Die Gefahr, onSaveInstanceState nicht zu verwenden und Speicher zu verwenden, ist die Gefahr, dass Android) dieser Speicher zurückerobert wird. Der gespeicherte Status wäre davon nicht betroffen, die Verwendung von Instanzvariablen oder versteckten Fragmenten würde jedoch dazu führen Datenverlust.

Wenn savedStateInstance null ist, muss kein Status wiederhergestellt werden.

Die Funktion if (values != null) soll lediglich vor der Möglichkeit schützen, dass kein Array gespeichert wurde. Wenn Sie jedoch Ihren ArrayAdapter für die Verarbeitung eines Null-Datensatzes codieren, benötigen Sie diesen nicht.

Wenn Ihre Zeilen Instanzen einer Ihrer eigenen Klassen und keine einzelnen Datenelemente sind, können Sie die Parcelable-Schnittstelle für diese Klasse implementieren und savedState.putParcelableArray("myKey", myArray) verwenden. Sie werden überrascht sein, wie nützlich es ist, Parcelable zu implementieren - es ermöglicht Ihnen, Ihre Klassen in Absichten weiterzugeben und viel saubereren Code zu schreiben.

56
Phil

Wenn das Gerät gedreht wird, wird die App neu gestartet. Also wird onSaveInstance aufgerufen, bevor die App zerstört wird. Sie können den Array-Adapter in onSaveInstance speichern. Wenn der onCreate beim nächsten Start der App endlich aufgerufen wird, können Sie den Array-Adapter abrufen und in die Listenansicht setzen.

6
Vikram Gupta

Es ist ziemlich einfach, die Elemente Ihres Adapters in onSaveInstance zu speichern.

Jetzt müssen Sie den Ort speichern (Scroll). Du kannst das

der einfache Weg

Da das Ändern von screenOrientation die Dinge sowieso durcheinander bringt, können Sie einen geringfügigen Fehler in Kauf nehmen und einfach das erste sichtbare Element in Ihrem onSaveInstance mit listView.getFirstVisiblePosition() speichern.

Dann können Sie in Ihrem onRestoreInstance diesen Index abrufen, um mit listview.setSelection(position) zum gleichen Element zu scrollen. Natürlich können Sie listview.smoothScrollToPosition(position) verwenden, aber das wäre seltsam.


auf die harte Tour

Um eine genauere Position zu erhalten, müssen Sie eine weitere Ebene nach unten gehen: Ermitteln Sie die Bildlaufposition (nicht den Index) und speichern Sie diese Position. Scrollen Sie dann nach der Wiederherstellung zu dieser Position zurück. Speichern Sie in Ihrem onSaveInstance die von listview.getScrollY() zurückgegebene Position. Wenn Sie diese Position in Ihrem onRestoreInstance abrufen, können Sie mit listview.scrollTo(0, position) zu dieser Position zurückblättern.


Warum ist es wirklich ein harter Weg?

Einfach. Sie können wahrscheinlich nicht zu dieser Position zurückblättern, da Ihre Listenansicht die Messung und das Layout noch nicht bestanden hat. Sie können dies umgehen, indem Sie nach dem Einstellen des Adapters mit getViewObserver().addOnGlobalLayoutListener auf das Layout warten. Stellen Sie in diesem Rückruf eine ausführbare Datei bereit, um zu der Position zu scrollen.


Ich rate, den ersten "einfachen Weg" zu wählen, da der Benutzer im Allgemeinen, wenn die Bildschirmausrichtung geändert wurde, wahrscheinlich seine Finger nach hinten bewegen wird. Wir müssen ihm nur die gleichen Gegenstände "Geben oder Nehmen" zeigen.

5
Sherif elKhatib

wenn sich die Ausrichtung ändert, ruft der Aktivitätslebenszyklus onPause und dann onRestart auf.

@Override
protected void onRestart() {
    super.onRestart();
    mAdapter.getFilter().filter(getFilterSettings());
    mAdapter.notifyDataSetChanged();
}
1
mjosh