Comment enregistrer la position de défilement de RecyclerView en utilisant RecyclerView.State?

J’ai une question à propos de Android RecyclerView.State .

J’utilise un RecyclerView, comment pourrais-je l’utiliser et le lier avec RecyclerView.State?

Mon but est de sauvegarder la position de défilement de RecyclerView .

    Comment prévoyez-vous de sauvegarder la dernière position enregistrée avec RecyclerView.State ?

    Vous pouvez toujours compter sur un bon état de sauvegarde. Étendez RecyclerView et remplacez onSaveInstanceState () et 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.getChildCount(); 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 CREATOR = new Parcelable.Creator() { @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); } @Override public SavedState[] newArray(int size) { return new SavedState[size]; } }; } 

    Si vous utilisez LinearLayoutManager, il est fourni avec save api linearLayoutManagerInstance.onSaveInstanceState () et restaure api linearLayoutManagerInstance.onRestoreInstanceState (…)

    Avec cela, vous pouvez enregistrer le colis retourné à votre état de sortie. par exemple,

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

    et restaurez la position de restauration avec l’état que vous avez enregistré. par exemple,

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

    Pour terminer, votre code final ressemblera à

     private static final Ssortingng 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()); } 

    Edit: Vous pouvez également utiliser le même fichier apis avec GridLayoutManager, car il s’agit d’une sous-classe de LinearLayoutManager. Merci @wegsehen pour la suggestion.

    Edit: Rappelez-vous que si vous chargez également des données dans un thread d’arrière-plan, vous devrez appeler onRestoreInstanceState dans votre méthode onPostExecute / onLoadFinished pour que la position soit restaurée après un changement d’orientation, par exemple

     @Override protected void onPostExecute(ArrayList movies) { mLoadingIndicator.setVisibility(View.INVISIBLE); if (movies != null) { showMoviePosterDataView(); mDataAdapter.setMovies(movies); mRecyclerView.getLayoutManager().onRestoreInstanceState(mSavedRecyclerLayoutState); } else { showErrorMessage(); } } 

    le magasin

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

    Restaurer

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

    et si cela ne fonctionne pas, essayez

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

    Mettez le store dans onPause() et restaurez dans onResume()

    I Définir les variables dans onCreate (), enregistrer la position du défilement dans onPause () et définir la position du défilement dans 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); } } 

    Je voulais enregistrer la position de défilement de Recycler View lorsque je me déplaçais en dehors de mon activité de liste, puis en cliquant sur le bouton Retour pour revenir en arrière. Beaucoup de solutions fournies pour ce problème étaient soit beaucoup plus compliquées que nécessaire ou ne fonctionnaient pas pour ma configuration, alors j’ai pensé partager ma solution.

    Sauvegardez d’abord votre état d’instance dans onPause, comme beaucoup l’ont montré. Je pense que cela vaut la peine de souligner ici que cette version de onSaveInstanceState est une méthode de la classe RecyclerView.LayoutManager.

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

    La clé pour que cela fonctionne correctement consiste à vous assurer d’appeler onRestoreInstanceState après avoir connecté votre adaptateur, comme certains l’ont indiqué dans d’autres threads. Cependant, l’appel de la méthode est beaucoup plus simple que ce que beaucoup ont indiqué.

     private void someMethod() { mVenueRecyclerView.setAdapter(mVenueAdapter); mLayoutManager.onRestoreInstanceState(state); } 

    Vous n’avez plus besoin de sauvegarder et de restaurer l’état par vous-même. Si vous définissez un ID unique dans xml et recyclerView.setSaveEnabled (true) (true par défaut), le système le fera automatiquement. Voici plus à ce sujet: http://sortingckyandroid.com/saving-android-view-state-correctly/

    Voici comment restaurer la position RecyclerView avec GridLayoutManager après la rotation lorsque vous devez recharger des données depuis Internet avec AsyncTaskLoader.

    Créez une variable globale de Parcelable et GridLayoutManager et une chaîne finale statique:

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

    Enregistrer l’état de gridLayoutManager dans onSaveInstance ()

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

    Restaurer dans 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); } } 

    Ensuite, lorsque le chargeur récupère des données à partir d’Internet, vous restaurez la position recyclée dans onLoadFinished ()

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

    .. bien sûr, vous devez instancier gridLayoutManager dans onCreate. À votre santé

    Pour moi, le problème était que je mettais en place un nouveau gestionnaire de mise en page chaque fois que je changeais d’adaptateur, perdant ainsi la position de défilement sur recyclerView.

    Voici mon approche pour les sauvegarder et maintenir l’état de recyclerview dans un fragment. Tout d’abord, ajoutez les modifications de configuration dans votre activité parent en tant que code ci-dessous.

     android:configChanges="orientation|screenSize" 

    Ensuite, dans votre fragment, déclarez ces méthodes d’instance

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

    Ajouter le code ci-dessous dans votre méthode @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().getSsortingng(R.ssortingng.recycler_scroll_position_key), mListState); } 

    Ajoutez la méthode onConfigartionChanged comme ci-dessous.

     @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().getSsortingng(R.ssortingng.recycler_scroll_position_key)); mTrailersRecyclerView.getLayoutManager().onRestoreInstanceState(mListState); } }, 50); } mTrailersRecyclerView.setLayoutManager(mLinearLayoutManager); } 

    Cette approche résoudra votre problème. Si vous avez un gestionnaire de disposition différent, remplacez simplement le gestionnaire de disposition supérieur.

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

    Pourquoi j’utilise OnSaveInstanceState() dans onPause() signifie que, tandis que passer à une autre activité, onPause serait appelée. Elle sauvegardera cette position de défilement et restaurera la position lorsque nous reviendrons d’une autre activité.