Comment enregistrer la position de défilement de RecyclerView à l'aide de RecyclerView.State?

108

J'ai une question sur RecyclerView.State d'Android .

J'utilise un RecyclerView, comment puis-je l'utiliser et le lier à RecyclerView.State?

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

陈文涛
la source

Réponses:

37

Comment comptez-vous enregistrer la dernière position enregistrée avec RecyclerView.State?

Vous pouvez toujours compter sur un bon état de sauvegarde. Étendez RecyclerViewet 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.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
la source
1
maintenant j'ai une autre question, comment, non, que peut faire RecyclerView.State?
陈文涛
4
ça marche vraiment? J'ai essayé cela, mais je continue à recevoir une exception d'exécution comme celle-ci: MyRecyclerView $ SavedState ne peut pas être converti en android.support.v7.widget.RecyclerView $ SavedState
Daivid
2
Sur l'état de l'instance de restauration, nous devons passer le superState à sa super classe (la vue recytcler) comme ceci: super.onRestoreInstanceState (((ScrollPositionSavingRecyclerView.SavedState) state) .getSuperState ());
micnoy
5
Cela ne fonctionne pas si vous étendez RecyclerView, vous obtiendrez BadParcelException.
EpicPandaForce
1
Rien de tout cela n'est nécessaire: si vous utilisez quelque chose comme LinearLayoutManager / GridLayoutManager, la "position de défilement" est déjà enregistrée automatiquement pour vous. (C'est la mAnchorPosition dans LinearLayoutManager.SavedState). Si vous ne voyez pas cela, c'est qu'il y a un problème avec la façon dont vous réappliquez les données.
Brian Yencho
230

Mettre à jour

À partir de la recyclerview:1.2.0-alpha02version, StateRestorationPolicya été introduit. Cela pourrait être une meilleure approche du problème donné.

Ce sujet a été couvert dans l' article moyen des développeurs Android .

De plus, @ rubén-viguera a partagé plus de détails dans la réponse ci-dessous. https://stackoverflow.com/a/61609823/892500

Ancienne réponse

Si vous utilisez LinearLayoutManager, il est livré avec une api de sauvegarde pré-construite linearLayoutManagerInstance.onSaveInstanceState () et une restauration de l'api linearLayoutManagerInstance.onRestoreInstanceState (...)

Avec cela, vous pouvez enregistrer le colis retourné dans votre état extérieur. 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 à quelque chose comme

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

Modifier: vous pouvez également utiliser les mêmes API avec GridLayoutManager, car il s'agit d'une sous-classe de LinearLayoutManager. Merci @wegsehen pour la suggestion.

Edit: Souvenez-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 lors du changement d'orientation, par exemple

@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
la source
21
C'est clairement la meilleure réponse, pourquoi n'est-elle pas acceptée? Notez que tout LayoutManager a cela, non seulement LinearLayoutManager, mais aussi GridLayoutManager, et sinon c'est une implémentation fausse.
Paul Woitaschek
linearLayoutManager.onInstanceState () renvoie toujours null -> vérifiez le code source. Malheureusement ne fonctionne pas.
luckyhandler
1
RecyclerView ne sauvegarde-t-il pas l'état de son LayoutManager dans son propre onSaveInstanceState? En regardant la version 24 de la bibliothèque de support ...
AndroidGuy
3
Cela fonctionne sur un seul RecyclerViewmais pas si vous avez un ViewPageravec un RecycerViewsur chaque page.
Kris B
1
@Ivan, je pense que cela fonctionne dans un fragment (juste vérifié), mais pas dans onCreateView, mais après le chargement des données. Voir la réponse de @Farmaker ici.
CoolMind
81

Boutique

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

Restaurer

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

et si cela ne fonctionne pas, essayez

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

Mettre le magasin onPause() et restaureronResume()

Gillis Haasnoot
la source
Cela fonctionne, mais vous devrez peut-être réinitialiser le lastFirstVisiblePositionaprès l' 0avoir restauré. Ce cas est utile lorsque vous avez un fragment / activité qui charge différentes données dans un RecyclerView, par exemple, une application d'exploration de fichiers.
blueware
Excellent! Cela satisfait à la fois le retour d'une activité de détail dans la liste et la sauvegarde de l'état lors de la rotation de l'écran
Javi
que faire si mon recyclerView est présent SwipeRefreshLayout?
Morozov
2
Pourquoi la première option de restauration ne fonctionnerait-elle pas, mais la seconde le ferait?
lucidbrot
1
@MehranJalili il semble être unRecyclerView
Vlad le
22

Je voulais enregistrer la position de défilement de Recycler View lors de la navigation loin de l'activité de ma liste, puis en cliquant sur le bouton de retour pour revenir en arrière. La plupart des solutions fournies pour ce problème étaient soit beaucoup plus compliquées que nécessaire ou ne fonctionnaient pas pour ma configuration, j'ai donc pensé partager ma solution.

Enregistrez d'abord l'état de votre instance dans onPause, comme beaucoup l'ont montré. Je pense qu'il 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 est de vous assurer que vous appelez onRestoreInstanceState après avoir connecté votre adaptateur, comme certains l'ont indiqué dans d'autres threads. Cependant, l'appel de méthode réel est beaucoup plus simple que beaucoup ne l'ont indiqué.

private void someMethod() {
    mVenueRecyclerView.setAdapter(mVenueAdapter);
    mLayoutManager.onRestoreInstanceState(state);
}
Braden Holt
la source
1
C'est la solution exacte. : D
Afjalur Rahman Rana
1
pour moi onSaveInstanceState n'est pas appelé, donc enregistrer l'état dans onPause semble être une meilleure option. im pop également la backstack pour revenir au fragment.
filthy_wizard
pour la charge en état. ce que je fais dans onViewCreated. il ne semble fonctionner que lorsque je suis en mode débogage et que j'utilise des points d'arrêt? ou si j'ajoute un délai et mets l'exécution dans une coroutine.
filthy_wizard
21

I Définir des variables dans onCreate (), enregistrer la position de défilement dans onPause () et définir la position de 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);
    }
}
farhad.kargaran
la source
Gardez également le décalage de l'article. Agréable. Merci!
t0m
14

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://trickyandroid.com/saving-android-view-state-correctly/

AppiDevo
la source
14

Tous les gestionnaires de mise en page inclus dans la bibliothèque de support savent déjà comment enregistrer et restaurer la position de défilement.

La position de défilement est restaurée lors de la première passe de mise en page, ce qui se produit lorsque les conditions suivantes sont remplies:

  • un gestionnaire de mise en page est attaché au RecyclerView
  • un adaptateur est attaché au RecyclerView

En règle générale, vous définissez le gestionnaire de mise en page en XML. Il ne vous reste donc plus qu'à

  1. Chargez l'adaptateur avec des données
  2. Fixez ensuite l'adaptateur auRecyclerView

Vous pouvez le faire à tout moment, ce n'est pas contraint à Fragment.onCreateViewou Activity.onCreate.

Exemple: assurez-vous que l'adaptateur est connecté à chaque fois que les données sont mises à jour.

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
    }
}

La position de défilement enregistrée est calculée à partir des données suivantes:

  • Position de l'adaptateur du premier élément à l'écran
  • Décalage en pixels du haut de l'élément par rapport au haut de la liste (pour la disposition verticale)

Par conséquent, vous pouvez vous attendre à une légère différence, par exemple si vos articles ont des dimensions différentes en orientation portrait et paysage.


Le RecyclerView/ ScrollView/ tout doit avoir un android:idpour que son état soit sauvegardé.

Eugen Pechanec
la source
C'était tout pour moi. J'étais en train de configurer l'adaptateur au départ, puis de mettre à jour ses données lorsque disponibles. Comme expliqué ci-dessus, le laisser jusqu'à ce que les données soient disponibles le fait revenir automatiquement à l'endroit où il se trouvait.
NeilS
Merci @Eugen. Existe-t-il une documentation sur la sauvegarde et la restauration de la position de défilement de LayoutManager?
Adam Hurwitz le
@AdamHurwitz À quel type de documentation vous attendez-vous? Ce que j'ai décrit est un détail d'implémentation de LinearLayoutManager, alors lisez son code source.
Eugen Pechanec
1
Voici un lien vers LinearLayoutManager.SavedState: cs.android.com/androidx/platform/frameworks/support
Eugen Pechanec
Merci, @EugenPechanec. Cela a fonctionné pour moi pour les rotations d'appareils. J'utilise également une vue de navigation inférieure et lorsque je passe à un autre onglet inférieur et que je reviens, la liste recommence depuis le début. Des idées sur pourquoi c'est?
schv09 le
4

Voici mon approche pour les sauvegarder et maintenir l'état de recyclage dans un fragment. Tout d'abord, ajoutez des modifications de configuration dans votre activité parentale comme 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;

Ajoutez 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().getString(R.string.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().getString(R.string.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 mise en page différent, remplacez simplement le gestionnaire de mise en page supérieur.

Pawan Kumar Sharma
la source
Vous n'avez peut-être pas besoin d'un gestionnaire pour les données persistantes. Les méthodes de cycle de vie seront suffisantes pour enregistrer / charger.
Mahi
@sayaMahi Pouvez-vous décrire correctement. J'ai également vu que onConfigurationChanged empêche d'appeler la méthode destroy. ce n'est donc pas une bonne solution.
Pawan kumar sharma
3

C'est ainsi que je restaure la position de RecyclerView avec GridLayoutManager après la rotation lorsque vous avez besoin de 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 String 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 sur Internet, vous restaurez la position de recyclage dans onLoadFinished ()

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

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

Agriculteur
la source
3

J'ai eu la même exigence, mais les solutions ici ne m'ont pas tout à fait permis de franchir la ligne, en raison de la source de données pour recyclerView.

J'extrayais l'état LinearLayoutManager de RecyclerViews dans onPause ()

private Parcelable state;

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

La parcelle stateest enregistrée onSaveInstanceState(Bundle outState)et extraite à nouveau dans onCreate(Bundle savedInstanceState), quand savedInstanceState != null.

Cependant, l'adaptateur recyclerView est rempli et mis à jour par un objet ViewModel LiveData renvoyé par un appel DAO à une base de données 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);
    }
});

J'ai finalement trouvé que la restauration de l'état de l'instance directement après la définition des données dans l'adaptateur conserverait l'état de défilement à travers les rotations.

Je soupçonne que cela est dû au fait que l' LinearLayoutManagerétat que j'avais restauré était en cours d'écrasement lorsque les données ont été renvoyées par l'appel de base de données, ou que l'état restauré n'avait aucun sens par rapport à un LinearLayoutManager `` vide ''.

Si les données de l'adaptateur sont disponibles directement (c'est-à-dire non contigentes lors d'un appel de base de données), la restauration de l'état de l'instance sur le LinearLayoutManager peut être effectuée une fois l'adaptateur défini sur le recyclerView.

La distinction entre les deux scénarios m'a tenu debout pendant des siècles.

MikeP
la source
3

Sur l'API Android niveau 28, je m'assure simplement de configurer mon LinearLayoutManageret RecyclerView.Adapterdans ma Fragment#onCreateViewméthode, et tout Just Worked ™ ️. Je n'avais pas besoin d'en faire onSaveInstanceStateou de onRestoreInstanceStatetravailler.

La réponse d'Eugen Pechanec explique pourquoi cela fonctionne.

Frontières de la santé
la source
2

À partir de la version 1.2.0-alpha02 de la bibliothèque androidx recyclerView, il est désormais géré automatiquement. Ajoutez-le simplement avec:

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

Et utilise:

adapter.stateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY

L'énumération StateRestorationPolicy a 3 options:

  • AUTORISER - l'état par défaut, qui restaure l'état RecyclerView immédiatement, au prochain passage de mise en page
  • PREVENT_WHEN_EMPTY - restaure l'état RecyclerView uniquement lorsque l'adaptateur n'est pas vide (adapter.getItemCount ()> 0). Si vos données sont chargées de manière asynchrone, le RecyclerView attend que les données soient chargées et alors seulement l'état est restauré. Si vous avez des éléments par défaut, comme des en-têtes ou des indicateurs de progression de chargement dans le cadre de votre adaptateur, vous devez utiliser l'option PREVENT, sauf si les éléments par défaut sont ajoutés à l'aide de MergeAdapter . MergeAdapter attend que tous ses adaptateurs soient prêts et ensuite seulement il restaure l'état.
  • PREVENT - toute restauration d'état est différée jusqu'à ce que vous définissiez ALLOW ou PREVENT_WHEN_EMPTY.

Notez qu'au moment de cette réponse, la bibliothèque recyclerView est toujours en alpha03, mais la phase alpha ne convient pas à des fins de production .

Rubén Viguera
la source
Tant de surmenage sauvé. Sinon, nous devions enregistrer l'index des clics de la liste, restaurer les éléments, empêcher le redessiner dans onCreateView, appliquer scrollToPosition (ou faire comme d'autres réponses) et pourtant l'utilisateur pouvait remarquer la différence après son retour
Rahul Kahale
De plus, si je veux enregistrer la position de RecyclerView après la navigation dans l'application ... existe-t-il un outil pour cela?
StayCool le
@RubenViguera Pourquoi alpha n'est pas à des fins de production? Je veux dire, est-ce vraiment mauvais?
StayCool le
1

Pour moi, le problème était que je configurais un nouveau layoutmanager chaque fois que je changeais mon adaptateur, perdant la position de défilement sur recyclerView.

Ronaldo Albertini
la source
1

Je voudrais juste partager la récente situation difficile que je rencontre avec le RecyclerView. J'espère que toute personne confrontée au même problème en bénéficiera.

Exigence de mon projet: J'ai donc un RecyclerView qui répertorie certains éléments cliquables dans mon activité principale (activité-A). Lorsque vous cliquez sur l'élément, une nouvelle activité s'affiche avec les détails de l'élément (activité-B).

J'ai implémenté dans le fichier Manifest le fait que Activity-A est le parent de Activity-B, de cette façon, j'ai un bouton de retour ou d'accueil sur l'ActionBar de Activity-B

Problème: chaque fois que j'ai appuyé sur le bouton Retour ou Accueil dans la barre d'action Activity-B, Activity-A entre dans le cycle de vie complet de l'activité à partir de onCreate ()

Même si j'ai implémenté un onSaveInstanceState () enregistrant la liste de l'adaptateur de RecyclerView, lorsque Activity-A démarre son cycle de vie, le saveInstanceState est toujours nul dans la méthode onCreate ().

En approfondissant Internet, je suis tombé sur le même problème, mais la personne a remarqué que le bouton Retour ou Accueil sous l'appareil Anroid (bouton Retour / Accueil par défaut) n'entre pas dans le cycle de vie de l'activité.

Solution:

  1. J'ai supprimé la balise de l'activité parent dans le manifeste de l'activité-B
  2. J'ai activé le bouton d'accueil ou de retour sur Activity-B

    Sous la méthode onCreate (), ajoutez cette ligne supportActionBar? .SetDisplayHomeAsUpEnabled (true)

  3. Dans la méthode onOptionsItemSelected (), j'ai vérifié l'élément item.ItemId sur lequel l'élément est cliqué en fonction de l'ID. L'identifiant du bouton de retour est

    android.R.id.home

    Ensuite, implémentez un appel de fonction finish () dans le fichier android.R.id.home

    Cela mettra fin à l'Activité-B et apportera Acitivy-A sans passer par tout le cycle de vie.

Pour mon besoin, c'est la meilleure solution à ce jour.

     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
la source
1

J'ai eu le même problème avec une différence mineure, j'utilisais la liaison de données et je définissais l'adaptateur recyclerView et le layoutManager dans les méthodes de liaison.

Le problème était que la liaison de données se produisait après onResume, donc cela réinitialisait mon layoutManager après onResume et cela signifie qu'il retournait à son emplacement d'origine à chaque fois. Ainsi, lorsque j'ai arrêté de définir layoutManager dans les méthodes d'adaptateur de liaison de données, cela fonctionne à nouveau correctement.

Amin Keshavarzian
la source
comment y êtes-vous parvenu?
Kedar Sukerkar le
0

Dans mon cas, je définissais le RecyclerView à la layoutManagerfois en XML et en onViewCreated. La suppression de l'affectation a été onViewCreatedcorrigée.

with(_binding.list) {
//  layoutManager =  LinearLayoutManager(context)
    adapter = MyAdapter().apply {
        listViewModel.data.observe(viewLifecycleOwner,
            Observer {
                it?.let { setItems(it) }
            })
    }
}
maxbeaudoin
la source
-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();

    }   

Pourquoi j'utilise OnSaveInstanceState()dans les onPause()moyens, alors que le passage à une autre activité onPause serait appelé.Il enregistrera cette position de défilement et restaurera la position lorsque nous revenons d'une autre activité.

Steve
la source
2
Le champ statique public n'est pas bon. Les données globales et les singletons ne sont pas bons.
weston
@weston J'ai compris maintenant, j'ai changé savestate en onpause pour supprimer global.
Steve