Jak zapisać pozycję przewijania RecyclerView za pomocą RecyclerView.State?

108

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 .

陈文涛
źródło

Odpowiedzi:

37

Jak planujesz zapisać ostatnią zapisaną pozycję RecyclerView.State?

Zawsze możesz polegać na starym dobrym stanie zapisu. Rozszerz RecyclerViewi 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];
            }
        };
    }
Nikola Despotoski
źródło
1
teraz mam inne pytanie, jak, nie, co może zrobić RecyclerView.State?
陈文涛
4
czy to naprawdę działa? Próbowałem tego, ale wciąż otrzymuję wyjątek w czasie wykonywania, taki jak ten: MyRecyclerView $ SavedState nie można przesłać do android.support.v7.widget.RecyclerView $ SavedState
Daivid
2
W stanie instancji przywracania musimy przekazać superState do jego superklasy (widok recytcler) w następujący sposób: super.onRestoreInstanceState (((ScrollPositionSavingRecyclerView.SavedState) stan) .getSuperState ());
micnoy
5
To nie zadziała, jeśli rozszerzysz RecyclerView, otrzymasz BadParcelException.
EpicPandaForce
1
Nic z tego nie jest konieczne: jeśli używasz czegoś takiego jak LinearLayoutManager / GridLayoutManager, „pozycja przewijania” jest już automatycznie zapisywana. (Jest to pozycja mAnchorPosition w LinearLayoutManager.SavedState). Jeśli tego nie widzisz, oznacza to, że coś jest nie tak ze sposobem ponownego stosowania danych.
Brian Yencho,
230

Aktualizacja

Począwszy od recyclerview:1.2.0-alpha02wydania StateRestorationPolicyzostał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,

outState.putParcelable("KeyForLayoutManagerState", linearLayoutManagerInstance.onSaveInstanceState());

i przywróć pozycję przywracania z zapisanym stanem. na przykład,

Parcelable state = savedInstanceState.getParcelable("KeyForLayoutManagerState");
linearLayoutManagerInstance.onRestoreInstanceState(state);

Podsumowując, ostateczny kod będzie wyglądał mniej więcej tak

private static final String BUNDLE_RECYCLER_LAYOUT = "classname.recycler.layout";

/**
 * This is a method for Fragment. 
 * You can do the same in onCreate or onRestoreInstanceState
 */
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
    super.onViewStateRestored(savedInstanceState);

    if(savedInstanceState != null)
    {
        Parcelable savedRecyclerLayoutState = savedInstanceState.getParcelable(BUNDLE_RECYCLER_LAYOUT);
        recyclerView.getLayoutManager().onRestoreInstanceState(savedRecyclerLayoutState);
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putParcelable(BUNDLE_RECYCLER_LAYOUT, recyclerView.getLayoutManager().onSaveInstanceState());
}

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.

@Override
protected void onPostExecute(ArrayList<Movie> movies) {
    mLoadingIndicator.setVisibility(View.INVISIBLE);
    if (movies != null) {
        showMoviePosterDataView();
        mDataAdapter.setMovies(movies);
      mRecyclerView.getLayoutManager().onRestoreInstanceState(mSavedRecyclerLayoutState);
        } else {
            showErrorMessage();
        }
    }
Gökhan Barış Aker
źródło
21
To zdecydowanie najlepsza odpowiedź, dlaczego nie jest to akceptowane? Zauważ, że każdy LayoutManager ma to, nie tylko LinearLayoutManager, ale także GridLayoutManager, a jeśli nie, jest to fałszywa implementacja.
Paul Woitaschek
linearLayoutManager.onInstanceState () zawsze zwraca null -> sprawdź kod źródłowy. Niestety nie działa.
luckyhandler
1
Czy RecyclerView nie zapisuje stanu swojego LayoutManager we własnym onSaveInstanceState? Patrząc na
wersję
3
Działa to na jedno RecyclerView, ale jeśli nie masz ViewPagerz RecycerViewkażdej strony.
Kris B
1
@Ivan, myślę, że działa we fragmencie (właśnie zaznaczone), ale nie w onCreateView, ale po załadowaniu danych. Zobacz odpowiedź @Farmaker tutaj.
CoolMind,
81

Sklep

lastFirstVisiblePosition = ((LinearLayoutManager)rv.getLayoutManager()).findFirstCompletelyVisibleItemPosition();

Przywracać

((LinearLayoutManager) rv.getLayoutManager()).scrollToPosition(lastFirstVisiblePosition);

a jeśli to nie zadziała, spróbuj

((LinearLayoutManager) rv.getLayoutManager()).scrollToPositionWithOffset(lastFirstVisiblePosition,0)

Włóż sklep onPause() i przywróćonResume()

Gillis Haasnoot
źródło
To działa, ale po przywróceniu może być konieczne zresetowanie lastFirstVisiblePositiondo 0. Ten przypadek jest przydatny, gdy masz fragment / działanie, które ładuje różne dane w jednym RecyclerView, na przykład w aplikacji eksploratora plików.
blueware
Doskonały! Spełnia zarówno powrót od szczegółowej aktywności do listy, jak i zapisanie stanu przy obracaniu ekranu
Javi
co zrobić, jeśli mój widok recyclingera jest włączony SwipeRefreshLayout?
Morozov
2
Dlaczego pierwsza opcja przywracania nie działałaby, a druga?
lucidbrot
1
@MehranJalili wygląda na to, że jest toRecyclerView
Vlad
22

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.

private LinearLayoutManager mLayoutManager;
Parcelable state;

        @Override
        public void onPause() {
            super.onPause();
            state = mLayoutManager.onSaveInstanceState();
        }

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.

private void someMethod() {
    mVenueRecyclerView.setAdapter(mVenueAdapter);
    mLayoutManager.onRestoreInstanceState(state);
}
Braden Holt
źródło
1
To jest dokładne rozwiązanie. : D
Afjalur Rahman Rana
1
dla mnie onSaveInstanceState nie jest nazywany, więc zapisywanie stanu w onPause wydaje się lepszą opcją. ja też wyskakuję z backstacka, aby wrócić do fragmentu.
filthy_wizard
dla ładunku w stanie. które robię w onViewCreated. wydaje się, że działa tylko wtedy, gdy jestem w trybie debugowania i używam punktów przerwania? lub jeśli dodam opóźnienie i umieszczę wykonanie w programie korygującym.
filthy_wizard
21

I Ustaw zmienne w onCreate (), zapisz pozycję przewijania w onPause () i ustaw pozycję przewijania w onResume ()

public static int index = -1;
public static int top = -1;
LinearLayoutManager mLayoutManager;

@Override
public void onCreate(Bundle savedInstanceState)
{
    //Set Variables
    super.onCreate(savedInstanceState);
    cRecyclerView = ( RecyclerView )findViewById(R.id.conv_recycler);
    mLayoutManager = new LinearLayoutManager(this);
    cRecyclerView.setHasFixedSize(true);
    cRecyclerView.setLayoutManager(mLayoutManager);

}

@Override
public void onPause()
{
    super.onPause();
    //read current recyclerview position
    index = mLayoutManager.findFirstVisibleItemPosition();
    View v = cRecyclerView.getChildAt(0);
    top = (v == null) ? 0 : (v.getTop() - cRecyclerView.getPaddingTop());
}

@Override
public void onResume()
{
    super.onResume();
    //set recyclerview position
    if(index != -1)
    {
        mLayoutManager.scrollToPositionWithOffset( index, top);
    }
}
farhad.kargaran
źródło
Zachowaj również przesunięcie elementu. Miły. Dzięki!
t0m
14

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/

AppiDevo
źródło
14

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:

  • menedżer układu jest dołączony do RecyclerView
  • adapter jest dołączony do RecyclerView

Zazwyczaj menedżer układu ustawiasz w XML, więc wszystko, co musisz teraz zrobić, to

  1. Załaduj adapter danymi
  2. Następnie podłącz adapter doRecyclerView

Możesz to zrobić w dowolnym momencie, nie jest to ograniczone do Fragment.onCreateViewaniActivity.onCreate .

Przykład: upewnij się, że adapter jest podłączony za każdym razem, gdy dane są aktualizowane.

viewModel.liveData.observe(this) {
    // Load adapter.
    adapter.data = it

    if (list.adapter != adapter) {
        // Only set the adapter if we didn't do it already.
        list.adapter = adapter
    }
}

Zapisana pozycja przewijania jest obliczana na podstawie następujących danych:

  • Położenie adaptera pierwszego elementu na ekranie
  • Przesunięcie piksela góry elementu od góry listy (dla układu pionowego)

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:idna stanie mają zostać zapisane.

Eugen Pechanec
źródło
To było to dla mnie. Najpierw ustawiałem adapter, a następnie aktualizowałem jego dane, gdy były dostępne. Jak wyjaśniono powyżej, pozostawienie go do czasu uzyskania danych powoduje automatyczne przewinięcie z powrotem do miejsca, w którym się znajdował.
NeilS,
Dzięki @Eugen. Czy istnieje dokumentacja dotycząca zapisywania i przywracania pozycji przewijania przez LayoutManager?
Adam Hurwitz
@AdamHurwitz Jakiej dokumentacji można się spodziewać? To, co opisałem, to szczegół implementacji LinearLayoutManager, więc przeczytaj jego kod źródłowy.
Eugen Pechanec
1
Oto link do LinearLayoutManager.SavedState: cs.android.com/androidx/platform/frameworks/support/+/…
Eugen Pechanec
Dzięki, @EugenPechanec. To zadziałało dla mnie przy obrotach urządzeń. Używam również dolnego widoku nawigacji, a kiedy przełączam się na inną dolną kartę i wracam, lista zaczyna się od początku. Jakieś pomysły, dlaczego tak jest?
schv09
4

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.

android:configChanges="orientation|screenSize"

Następnie w swoim fragmencie zadeklaruj te metody wystąpienia

private  Bundle mBundleRecyclerViewState;
private Parcelable mListState = null;
private LinearLayoutManager mLinearLayoutManager;

Dodaj poniższy kod w swojej metodzie @onPause

@Override
public void onPause() {
    super.onPause();
    //This used to store the state of recycler view
    mBundleRecyclerViewState = new Bundle();
    mListState =mTrailersRecyclerView.getLayoutManager().onSaveInstanceState();
    mBundleRecyclerViewState.putParcelable(getResources().getString(R.string.recycler_scroll_position_key), mListState);
}

Dodaj metodę onConfigartionChanged, jak poniżej.

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    //When orientation is changed then grid column count is also changed so get every time
    Log.e(TAG, "onConfigurationChanged: " );
    if (mBundleRecyclerViewState != null) {
        new Handler().postDelayed(new Runnable() {

            @Override
            public void run() {
                mListState = mBundleRecyclerViewState.getParcelable(getResources().getString(R.string.recycler_scroll_position_key));
                mTrailersRecyclerView.getLayoutManager().onRestoreInstanceState(mListState);

            }
        }, 50);
    }
    mTrailersRecyclerView.setLayoutManager(mLinearLayoutManager);
}

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.

Pawan Kumar Sharma
źródło
Możesz nie potrzebować obsługi do utrwalania danych. Metody cyklu życia wystarczą do zapisania / załadowania.
Mahi
@sayaMahi Czy możesz opisać to we właściwy sposób. Widziałem również, że onConfigurationChanged zapobiega wywołaniu metody zniszczenia. więc nie jest to właściwe rozwiązanie.
Pawan Kumar Sharma
3

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:

private Parcelable savedRecyclerLayoutState;
private GridLayoutManager mGridLayoutManager;
private static final String BUNDLE_RECYCLER_LAYOUT = "recycler_layout";

Zapisz stan gridLayoutManager w onSaveInstance ()

 @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putParcelable(BUNDLE_RECYCLER_LAYOUT, 
            mGridLayoutManager.onSaveInstanceState());
        }

Przywróć w onRestoreInstanceState

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);

        //restore recycler view at same position
        if (savedInstanceState != null) {
            savedRecyclerLayoutState = savedInstanceState.getParcelable(BUNDLE_RECYCLER_LAYOUT);
        }
    }

Następnie, gdy program ładujący pobiera dane z Internetu, przywracasz pozycję widoku recyklingu w onLoadFinished ()

if(savedRecyclerLayoutState!=null){
                mGridLayoutManager.onRestoreInstanceState(savedRecyclerLayoutState);
            }

.. oczywiście musisz utworzyć wystąpienie gridLayoutManager w onCreate. Twoje zdrowie

Farmer
źródło
3

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 ()

private Parcelable state;

Public void onPause() {
    state = mLinearLayoutManager.onSaveInstanceState();
}

Przesyłka statejest zapisywana onSaveInstanceState(Bundle outState)i ponownie wypakowywana onCreate(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.

mViewModel.getAllDataToDisplay(mSelectedData).observe(this, new Observer<List<String>>() {
    @Override
    public void onChanged(@Nullable final List<String> displayStrings) {
        mAdapter.swapData(displayStrings);
        mLinearLayoutManager.onRestoreInstanceState(state);
    }
});

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.

MikeP
źródło
3

Android API Level 28, ja po prostu upewnić się, że ja skonfigurować LinearLayoutManageri RecyclerView.Adaptermoim Fragment#onCreateViewsposobem, a wszystko po prostu Pracował ™ ️. Nie musiałem nic robić onSaveInstanceStateani onRestoreInstanceStatepracować.

Odpowiedź Eugena Pechaneca wyjaśnia, dlaczego to działa.

Heath Borders
źródło
2

Począwszy od wersji 1.2.0-alpha02 biblioteki androidx reclerView, jest teraz zarządzana automatycznie. Po prostu dodaj za pomocą:

implementation "androidx.recyclerview:recyclerview:1.2.0-alpha02"

I użyć:

adapter.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY

Wyliczenie StateRestorationPolicy ma 3 opcje:

  • ALLOW - stan domyślny, który natychmiast przywraca stan RecyclerView w następnym przebiegu układu
  • PREVENT_WHEN_EMPTY - odtwarza stan RecyclerView tylko wtedy, gdy adapter nie jest pusty (adapter.getItemCount ()> 0). Jeśli dane są ładowane asynchronicznie, RecyclerView czeka, aż dane zostaną załadowane i dopiero wtedy stan zostanie przywrócony. Jeśli masz domyślne elementy, takie jak nagłówki lub wskaźniki postępu ładowania jako część adaptera, powinieneś użyć opcji ZAPOBIEGANIE, chyba że domyślne elementy są dodawane za pomocą MergeAdapter . MergeAdapter czeka, aż wszystkie jego adaptery będą gotowe i dopiero wtedy przywraca stan.
  • ZAPOBIEGANIE - przywrócenie wszystkich stanów jest odroczone do momentu ustawienia ZEZWOLENIA lub PREVENT_WHEN_EMPTY.

Zauważ, że w czasie tej odpowiedzi biblioteka recyclinglerView jest nadal w wersji alpha03, ale faza alfa nie jest odpowiednia do celów produkcyjnych .

Rubén Viguera
źródło
Zaoszczędzono tyle przepracowania. W przeciwnym razie musieliśmy zapisać indeks kliknięć listy, przywrócić elementy, zapobiec przerysowaniu w onCreateView, zastosować scrollToPosition (lub zrobić tak jak inne odpowiedzi), a mimo to użytkownik mógł zauważyć różnicę po powrocie
Rahul Kahale
Ponadto, jeśli chcę zapisać pozycję RecyclerView po nawigacji po aplikacji ... czy jest do tego jakieś narzędzie?
StayCool
@RubenViguera Dlaczego alfa nie jest przeznaczona do celów produkcyjnych? Mam na myśli, czy to naprawdę źle?
StayCool
1

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.

Ronaldo Albertini
źródło
1

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:

  1. Usunąłem tag dla działania nadrzędnego w manifeście dla Activity-B
  2. Włączyłem przycisk Home lub Back w Activity-B

    W metodzie onCreate () dodaj tę linię supportActionBar? .SetDisplayHomeAsUpEnabled (true)

  3. 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.

     override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_show_project)

    supportActionBar?.title = projectName
    supportActionBar?.setDisplayHomeAsUpEnabled(true)

}


 override fun onOptionsItemSelected(item: MenuItem?): Boolean {

    when(item?.itemId){

        android.R.id.home -> {
            finish()
        }
    }

    return super.onOptionsItemSelected(item)
}
Andy Parinas
źródło
1

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.

Amin Keshavarzian
źródło
jak to osiągnąłeś?
Kedar Sukerkar
0

W moim przypadku ustawiałem RecyclerView layoutManagerzarówno w XML, jak iw onViewCreated. Usunięcie zadania onViewCreatednaprawiło to.

with(_binding.list) {
//  layoutManager =  LinearLayoutManager(context)
    adapter = MyAdapter().apply {
        listViewModel.data.observe(viewLifecycleOwner,
            Observer {
                it?.let { setItems(it) }
            })
    }
}
maxbeaudoin
źródło
-1

Activity.java:

public RecyclerView.LayoutManager mLayoutManager;

Parcelable state;

    mLayoutManager = new LinearLayoutManager(this);


// Inside `onCreate()` lifecycle method, put the below code :

    if(state != null) {
    mLayoutManager.onRestoreInstanceState(state);

    } 

    @Override
    protected void onResume() {
        super.onResume();

        if (state != null) {
            mLayoutManager.onRestoreInstanceState(state);
        }
    }   

   @Override
    protected void onPause() {
        super.onPause();

        state = mLayoutManager.onSaveInstanceState();

    }   

Dlaczego używam OnSaveInstanceState()w onPause()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.

Steve
źródło
2
Pole statyczne Public nie jest dobre. Globalne dane i singletony nie są dobre.
weston
@weston Teraz zrozumiałem. Zmieniłem savestate na onpause, aby usunąć global.
Steve