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 .
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 .
Comment comptez-vous enregistrer 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.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];
}
};
}
Mettre à jour
À partir de la
recyclerview:1.2.0-alpha02
version,StateRestorationPolicy
a é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,
et restaurez la position de restauration avec l'état que vous avez enregistré. par exemple,
Pour terminer, votre code final ressemblera à quelque chose comme
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
la source
RecyclerView
mais pas si vous avez unViewPager
avec unRecycerView
sur chaque page.onCreateView
, mais après le chargement des données. Voir la réponse de @Farmaker ici.Boutique
Restaurer
et si cela ne fonctionne pas, essayez
Mettre le magasin
onPause()
et restaureronResume()
la source
lastFirstVisiblePosition
après l'0
avoir restauré. Ce cas est utile lorsque vous avez un fragment / activité qui charge différentes données dans unRecyclerView
, par exemple, une application d'exploration de fichiers.SwipeRefreshLayout
?RecyclerView
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.
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é.
la source
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 ()
la source
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/
la source
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:
RecyclerView
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'à
RecyclerView
Vous pouvez le faire à tout moment, ce n'est pas contraint à
Fragment.onCreateView
ouActivity.onCreate
.Exemple: assurez-vous que l'adaptateur est connecté à chaque fois que les données sont mises à jour.
La position de défilement enregistrée est calculée à partir des données suivantes:
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 unandroid:id
pour que son état soit sauvegardé.la source
LinearLayoutManager.SavedState
: cs.android.com/androidx/platform/frameworks/supportVoici 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.
Ensuite, dans votre Fragment, déclarez ces méthodes d'instance
Ajoutez le code ci-dessous dans votre méthode @onPause
Ajoutez la méthode onConfigartionChanged comme ci-dessous.
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.
la source
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:
Enregistrer l'état de gridLayoutManager dans onSaveInstance ()
Restaurer dans onRestoreInstanceState
Ensuite, lorsque le chargeur récupère des données sur Internet, vous restaurez la position de recyclage dans onLoadFinished ()
.. Bien sûr, vous devez instancier gridLayoutManager dans onCreate. À votre santé
la source
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 ()
La parcelle
state
est enregistréeonSaveInstanceState(Bundle outState)
et extraite à nouveau dansonCreate(Bundle savedInstanceState)
, quandsavedInstanceState != 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.
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.
la source
Sur l'API Android niveau 28, je m'assure simplement de configurer mon
LinearLayoutManager
etRecyclerView.Adapter
dans maFragment#onCreateView
méthode, et tout Just Worked ™ ️. Je n'avais pas besoin d'en faireonSaveInstanceState
ou deonRestoreInstanceState
travailler.La réponse d'Eugen Pechanec explique pourquoi cela fonctionne.
la source
À 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:
Et utilise:
L'énumération StateRestorationPolicy a 3 options:
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 .
la source
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.
la source
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:
J'ai activé le bouton d'accueil ou de retour sur Activity-B
Sous la méthode onCreate (), ajoutez cette ligne supportActionBar? .SetDisplayHomeAsUpEnabled (true)
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.
la source
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.
la source
Dans mon cas, je définissais le RecyclerView à la
layoutManager
fois en XML et enonViewCreated
. La suppression de l'affectation a étéonViewCreated
corrigée.la source
Activity.java:
Pourquoi j'utilise
OnSaveInstanceState()
dans lesonPause()
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é.la source