Mam pytanie dotyczące programu RecyclerView.State w systemie Android .
Używam RecyclerView, jak mogę go użyć i powiązać z RecyclerView.State?
Moim celem jest zapisanie pozycji przewijania RecyclerView .
Mam pytanie dotyczące programu RecyclerView.State w systemie Android .
Używam RecyclerView, jak mogę go użyć i powiązać z RecyclerView.State?
Moim celem jest zapisanie pozycji przewijania RecyclerView .
Jak planujesz zapisać ostatnią zapisaną pozycję RecyclerView.State
?
Zawsze możesz polegać na starym dobrym stanie zapisu. Rozszerz RecyclerView
i zastąp onSaveInstanceState () i onRestoreInstanceState()
:
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
LayoutManager layoutManager = getLayoutManager();
if(layoutManager != null && layoutManager instanceof LinearLayoutManager){
mScrollPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
}
SavedState newState = new SavedState(superState);
newState.mScrollPosition = mScrollPosition;
return newState;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
if(state != null && state instanceof SavedState){
mScrollPosition = ((SavedState) state).mScrollPosition;
LayoutManager layoutManager = getLayoutManager();
if(layoutManager != null){
int count = layoutManager.getItemCount();
if(mScrollPosition != RecyclerView.NO_POSITION && mScrollPosition < count){
layoutManager.scrollToPosition(mScrollPosition);
}
}
}
}
static class SavedState extends android.view.View.BaseSavedState {
public int mScrollPosition;
SavedState(Parcel in) {
super(in);
mScrollPosition = in.readInt();
}
SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(mScrollPosition);
}
public static final Parcelable.Creator<SavedState> CREATOR
= new Parcelable.Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
Aktualizacja
Począwszy od
recyclerview:1.2.0-alpha02
wydaniaStateRestorationPolicy
zostało wprowadzone. To mogłoby być lepsze podejście do danego problemu.Ten temat został omówiony w średnim artykule dla programistów Androida .
Ponadto @ rubén-viguera udostępnił więcej szczegółów w odpowiedzi poniżej. https://stackoverflow.com/a/61609823/892500
Stara odpowiedź
Jeśli używasz LinearLayoutManager, jest dostarczany z gotowym zapisem API linearLayoutManagerInstance.onSaveInstanceState () i przywracaniem interfejsu API linearLayoutManagerInstance.onRestoreInstanceState (...)
Dzięki temu możesz zapisać zwróconą paczkę w swoim OutState. na przykład,
i przywróć pozycję przywracania z zapisanym stanem. na przykład,
Podsumowując, ostateczny kod będzie wyglądał mniej więcej tak
Edycja: tego samego interfejsu API można również używać z GridLayoutManager, ponieważ jest to podklasa LinearLayoutManager. Dzięki @wegsehen za sugestię.
Edycja: Pamiętaj, że jeśli ładujesz również dane w wątku w tle, będziesz musiał wywołać onRestoreInstanceState w ramach metody onPostExecute / onLoadFinished, aby pozycja została przywrócona po zmianie orientacji, np.
źródło
RecyclerView
, ale jeśli nie maszViewPager
zRecycerView
każdej strony.onCreateView
, ale po załadowaniu danych. Zobacz odpowiedź @Farmaker tutaj.Sklep
Przywracać
a jeśli to nie zadziała, spróbuj
Włóż sklep
onPause()
i przywróćonResume()
źródło
lastFirstVisiblePosition
do0
. Ten przypadek jest przydatny, gdy masz fragment / działanie, które ładuje różne dane w jednymRecyclerView
, na przykład w aplikacji eksploratora plików.SwipeRefreshLayout
?RecyclerView
Chciałem zapisać pozycję przewijania Recycler View podczas opuszczania mojej listy aktywności, a następnie kliknięcia przycisku Wstecz, aby przejść wstecz. Wiele rozwiązań przedstawionych dla tego problemu było albo o wiele bardziej skomplikowanych niż było to konieczne, lub nie działało w mojej konfiguracji, więc pomyślałem, że podzielę się swoim rozwiązaniem.
Najpierw zapisz stan instancji w onPause, jak wiele osób pokazało. Myślę, że warto tu podkreślić, że ta wersja onSaveInstanceState jest metodą z klasy RecyclerView.LayoutManager.
Kluczem do poprawnego działania tego rozwiązania jest upewnienie się, że wywołujesz onRestoreInstanceState po podłączeniu adaptera, jak niektórzy wskazywali w innych wątkach. Jednak rzeczywiste wywołanie metody jest znacznie prostsze niż wiele osób wskazywało.
źródło
I Ustaw zmienne w onCreate (), zapisz pozycję przewijania w onPause () i ustaw pozycję przewijania w onResume ()
źródło
Nie musisz już samodzielnie zapisywać i przywracać stanu. Jeśli ustawisz unikalny identyfikator w xml i recyklerView.setSaveEnabled (true) (domyślnie true) system automatycznie to zrobi. Tutaj jest więcej na ten temat: http://trickyandroid.com/saving-android-view-state-correctly/
źródło
Wszyscy menedżerowie układów w bibliotece wsparcia już wiedzą, jak zapisywać i przywracać pozycję przewijania.
Pozycja przewijania jest przywracana przy pierwszym przebiegu układu, co ma miejsce, gdy spełnione są następujące warunki:
RecyclerView
RecyclerView
Zazwyczaj menedżer układu ustawiasz w XML, więc wszystko, co musisz teraz zrobić, to
RecyclerView
Możesz to zrobić w dowolnym momencie, nie jest to ograniczone do
Fragment.onCreateView
aniActivity.onCreate
.Przykład: upewnij się, że adapter jest podłączony za każdym razem, gdy dane są aktualizowane.
Zapisana pozycja przewijania jest obliczana na podstawie następujących danych:
Dlatego możesz spodziewać się niewielkich niedopasowań, np. Jeśli Twoje przedmioty mają różne wymiary w orientacji pionowej i poziomej.
RecyclerView
/ScrollView
/ Cokolwiek musi miećandroid:id
na stanie mają zostać zapisane.źródło
LinearLayoutManager.SavedState
: cs.android.com/androidx/platform/frameworks/support/+/…Oto moje Podejście do ich uratowania i utrzymania stanu recyklingu w fragmentach. Najpierw dodaj zmiany konfiguracji w swojej aktywności rodzica, jak poniżej.
Następnie w swoim fragmencie zadeklaruj te metody wystąpienia
Dodaj poniższy kod w swojej metodzie @onPause
Dodaj metodę onConfigartionChanged, jak poniżej.
To rozwiązanie rozwiąże Twój problem. jeśli masz innego menedżera układu, po prostu zastąp górnego menedżera układu.
źródło
W ten sposób przywracam pozycję RecyclerView za pomocą GridLayoutManager po obróceniu, gdy trzeba ponownie załadować dane z Internetu za pomocą AsyncTaskLoader.
Utwórz zmienną globalną Parcelable i GridLayoutManager oraz statyczny ciąg końcowy:
Zapisz stan gridLayoutManager w onSaveInstance ()
Przywróć w onRestoreInstanceState
Następnie, gdy program ładujący pobiera dane z Internetu, przywracasz pozycję widoku recyklingu w onLoadFinished ()
.. oczywiście musisz utworzyć wystąpienie gridLayoutManager w onCreate. Twoje zdrowie
źródło
Miałem ten sam wymóg, ale przedstawione tutaj rozwiązania nie do końca pozwoliły mi przejść przez linię, ze względu na źródło danych dla recyclinglerView.
Wyodrębniałem stan LinearLayoutManager RecyclerViews w onPause ()
Przesyłka
state
jest zapisywanaonSaveInstanceState(Bundle outState)
i ponownie wypakowywanaonCreate(Bundle savedInstanceState)
, kiedysavedInstanceState != null
.Jednak adapter recyklerView jest wypełniany i aktualizowany przez obiekt ViewModel LiveData zwracany przez wywołanie DAO do bazy danych Room.
W końcu stwierdziłem, że przywrócenie stanu instancji bezpośrednio po ustawieniu danych w adapterze zachowuje stan przewijania między obrotami.
Podejrzewam, że to też jest spowodowane tym
LinearLayoutManager
że stan, który przywróciłem, był nadpisywany, gdy dane zostały zwrócone przez wywołanie bazy danych, lub stan przywrócenia był bez znaczenia dla „pustego” LinearLayoutManager.Jeśli dane adaptera są dostępne bezpośrednio (tj. Nie są zależne od wywołania bazy danych), wówczas przywrócenie stanu instancji w LinearLayoutManager można wykonać po ustawieniu adaptera w recyklinguView.
Różnica między tymi dwoma scenariuszami trzymała mnie w napięciu na wieki.
źródło
Android API Level 28, ja po prostu upewnić się, że ja skonfigurować
LinearLayoutManager
iRecyclerView.Adapter
moimFragment#onCreateView
sposobem, a wszystko po prostu Pracował ™ ️. Nie musiałem nic robićonSaveInstanceState
anionRestoreInstanceState
pracować.Odpowiedź Eugena Pechaneca wyjaśnia, dlaczego to działa.
źródło
Począwszy od wersji 1.2.0-alpha02 biblioteki androidx reclerView, jest teraz zarządzana automatycznie. Po prostu dodaj za pomocą:
I użyć:
Wyliczenie StateRestorationPolicy ma 3 opcje:
Zauważ, że w czasie tej odpowiedzi biblioteka recyclinglerView jest nadal w wersji alpha03, ale faza alfa nie jest odpowiednia do celów produkcyjnych .
źródło
Dla mnie problem polegał na tym, że za każdym razem, gdy zmieniałem adapter, konfigurowałem nowy layoutmanager, tracąc pozycję przewijania kolejki w programie recyclinglerView.
źródło
Chciałbym tylko podzielić się ostatnimi kłopotami, które napotykam z RecyclerView. Mam nadzieję, że skorzysta każdy, kto ma ten sam problem.
Wymagania mojego projektu: Mam więc widok RecyclerView, który zawiera listę niektórych elementów, które można kliknąć, w moim głównym działaniu (działanie-A). Po kliknięciu elementu zostanie wyświetlone nowe działanie ze szczegółami elementu (działanie-B).
Wdrożyłem w Manifeście pliku , że Activity-A jest rodzicem Activity-B, w ten sposób mam przycisk Wstecz lub Home na ActionBar Activity-B
Problem: Za każdym razem, gdy nacisnąłem przycisk Wstecz lub Strona główna na pasku akcji Activity-B, Activity-A przechodzi do pełnego cyklu życia działania, zaczynając od onCreate ()
Mimo że zaimplementowałem onSaveInstanceState () zapisując listę adaptera RecyclerView, gdy Activity-A rozpoczyna swój cykl życia, saveInstanceState jest zawsze null w metodzie onCreate ().
Dalsze kopanie w Internecie napotkałem ten sam problem, ale osoba zauważyła, że przycisk Wstecz lub Strona główna pod urządzeniem Anroid (domyślny przycisk Wstecz / Strona główna) Aktywność-A nie przechodzi do cyklu życia aktywności.
Rozwiązanie:
Włączyłem przycisk Home lub Back w Activity-B
W metodzie onCreate () dodaj tę linię supportActionBar? .SetDisplayHomeAsUpEnabled (true)
W metodzie overide fun onOptionsItemSelected () sprawdziłem item.ItemId, na który element został kliknięty na podstawie id. Identyfikator przycisku Wstecz to
android.R.id.home
Następnie zaimplementuj wywołanie funkcji finish () w android.R.id.home
To zakończy działanie B i przyniesie Acitivy-A bez przechodzenia przez cały cykl życia.
Jak na moje wymagania jest to dotychczas najlepsze rozwiązanie.
źródło
Miałem ten sam problem z niewielką różnicą, korzystałem z Databinding i ustawiałem adaptera recyclinglerView i layoutManager w metodach wiązania.
Problem polegał na tym, że wiązanie danych miało miejsce po onResume, więc resetował mój layoutManager po onResume, a to oznacza, że za każdym razem przewijał się z powrotem do pierwotnego miejsca. Więc kiedy przestałem ustawiać layoutManager w metodach adaptera Databinding, znowu działa dobrze.
źródło
W moim przypadku ustawiałem RecyclerView
layoutManager
zarówno w XML, jak iwonViewCreated
. Usunięcie zadaniaonViewCreated
naprawiło to.źródło
Activity.java:
Dlaczego używam
OnSaveInstanceState()
wonPause()
oznacza, że przełączenie do innej czynności zostanie wywołane onPause, zapisze tę pozycję przewijania i przywróci pozycję, gdy wrócimy z innej czynności.źródło