Bonne solution pour conserver les éléments de listview lorsque l’utilisateur fait pivoter le téléphone et conserve toutes les données dans ArrayAdapter

J’utilise Fragment avec listView. Je remplis ArrayAdapter associé à cette liste, par les données reçues dans Custom Loader (à partir d’Internet). Custom ArrayAdapter prend en charge le défilement infini (pagination).

Quel est le meilleur moyen de stocker des éléments dans ArrayAdapter lorsque l’utilisateur fait pivoter le périphérique et conserve sa position de défilement dans ListView?

Je pense à la création d’un fragment non visuel avec ArrayAdapter et à la méthode setRetainInstance pour enregistrer les valeurs.

Des suggestions pour une meilleure solution?

Pour travailler avec le framework Android et le cycle de vie Fragment, vous devez implémenter la méthode onSaveInstanceState dans votre fragment. Pour simplifier, je suppose que vous avez un tableau de valeurs Ssortingng auquel vous pouvez accéder (j’étends généralement ArrayAdapter pour encapsuler la construction de la vue et fournir une méthode pratique pour accéder à l’ensemble du jeu de données sous-jacent):

 public void onSaveInstanceState(Bundle savedState) { super.onSaveInstanceState(savedState); // Note: getValues() is a method in your ArrayAdapter subclass Ssortingng[] values = mAdapter.getValues(); savedState.putSsortingngArray("myKey", values); } 

Vous pouvez alors récupérer les données dans votre méthode onCreate (ou onCreateView ou onActivityCreated – voir le fragment JavaDoc ) comme ceci:

 public void onCreate (Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { Ssortingng[] values = savedInstanceState.getSsortingngArray("myKey"); if (values != null) { mAdapter = new MyAdapter(values); } } ... } 

Cela garantit que tous les événements du cycle de vie seront traités correctement, sans perte de données, y compris la rotation du périphérique et le passage de l’utilisateur à d’autres applications. Le danger de ne pas utiliser onSaveInstanceState et d’utiliser la mémoire est le danger d’Android à récupérer cette mémoire. L’état enregistré ne serait pas affecté par cela, mais l’utilisation de variables d’instance ou de fragments cachés entraînerait une perte de données.

Si savedStateInstance est null, il n’y a pas d’état à restaurer.

Le if (values != null) sert simplement à empêcher la possibilité qu’aucun tableau n’ait été enregistré, mais si vous codez votre ArrayAdapter pour gérer un dataset null, vous n’en aurez pas besoin.

La solution ultime, si vos lignes sont des instances d’une de vos propres classes et non des éléments de données uniques, consiste à implémenter l’interface Parcelable sur cette classe, vous pouvez alors utiliser savedState.putParcelableArray("myKey", myArray) . Vous seriez surpris de voir à quel point il est utile de savoir comment implémenter Parcelable – cela vous permet de passer vos cours à l’intérieur de vos intentions et d’écrire du code beaucoup plus propre.

Lorsque le périphérique est pivoté, l’application est redémarrée. Donc onSaveInstance est appelé avant que l’application ne soit détruite. Vous pouvez enregistrer l’adaptateur de tableau dans onSaveInstance et, lorsque l’ onCreate est finalement lancé au redémarrage de l’application, vous pouvez récupérer l’adaptateur de tableau et le définir dans l’affichage de liste.

Il est assez facile de sauvegarder les éléments de votre adaptateur dans onSaveInstance .

Maintenant, vous devez enregistrer l’emplacement (Défilement). Tu peux le faire

la manière facile

Comme changer de screenOrientation va de toute façon gâcher les choses, vous pouvez permettre une erreur marginale et, simplement, dans votre onSaveInstance , enregistrez le premier élément visible en utilisant listView.getFirstVisiblePosition() .

Ensuite, dans votre onRestoreInstance vous pouvez récupérer cet index pour accéder au même élément en utilisant listview.setSelection(position) . Bien sûr, vous pouvez utiliser listview.smoothScrollToPosition(position) mais ce serait bizarre.


à la dure

Pour avoir une position plus exacte, vous devrez descendre d’un niveau de plus: Obtenez la position de défilement (pas d’index) et sauvegardez cette position. Ensuite, après la restauration, revenez à cette position. Dans votre onSaveInstance , enregistrez la position renvoyée par listview.getScrollY() . Lorsque vous récupérez cette position dans votre onRestoreInstance , vous pouvez revenir à cette position en utilisant listview.scrollTo(0, position) .


Pourquoi est-ce vraiment difficile?

Simple. Vous ne pourrez probablement pas revenir à cette position car votre listview n’aura pas encore passé la mesure et la mise en page. Vous pouvez résoudre ce problème en attendant la mise en page après avoir configuré l’adaptateur à l’aide de getViewObserver().addOnGlobalLayoutListener . Dans ce rappel, publiez un fichier exécutable pour accéder à la position.


Je vous conseille d’utiliser le premier “moyen facile” car en général, lorsque l’orientation de l’écran a été modifiée, l’utilisateur remettra probablement ses doigts en arrière. Nous avons juste besoin de lui montrer les mêmes éléments “donner ou prendre”.

lorsque l’orientation change l’activité cycle de vie appelle onPause puis onRestart Faites quelque chose comme ça –

 @Override protected void onRestart() { super.onRestart(); mAdapter.getFilter().filter(getFilterSettings()); mAdapter.notifyDataSetChanged(); } 

Je ne connais pas le contenu de votre ArrayAdapter ou de la List sauvegarde, mais qu’en est-il de la ArrayAdapter sérialiser les données sauvegardées, de les enregistrer et de les charger lorsque la vue est recréée?

Traditionnellement, cette approche a été utilisée lorsque vous essayez de stocker des données lorsque l’application est en cours de fermeture ou risque de ne pas restr en arrière-plan. Il y a un excellent post sur la sérialisation avec un exemple de code ici. Ils parcourent une ArrayList d’objects personnalisés, l’écrivent dans un fichier et le rouvrent ultérieurement. Je pense que si vous avez implémenté cette approche, en écrivant les données de votre List support ou ArrayAdapter dans onPause() avant que l’activité soit détruite, vous pouvez alors recharger ce fichier lorsque l’activité est recréée.

Autres approches (plans de sauvegarde a / k / a):

(1) Facile mais négligé – Si votre liste est primitive, comme une liste de chaînes, vous pouvez toujours envisager d’écrire les valeurs individuellement dans SharedPreferences et de les récupérer lors du rechargement. Veillez simplement à atsortingbuer un identifiant unique au processus de stockage.

NOTE SharedPreferecnes que cela puisse fonctionner, SharedPreferecnes n’est généralement pas conçu pour gérer de grandes quantités de données. Par conséquent, si votre liste est longue, SharedPreferecnes cette approche. Pour quelques points de données, cependant, je ne vois pas de problème.

(2) Légèrement plus difficile mais risqué – Si vous sauvegardez la List , l’adaptateur contient des objects qui implémentent parcelable ou sont déjà sérialisables, envisagez de transmettre la List via une Intent à une activité existante en arrière-plan et en utilisant un rappel pour récupérer ces données lorsque l’activité est recréée. Ceci est similaire à votre idée de créer un Fragment fond. Les deux approches courent le risque que l’ Activity ou le Fragment vous ciblez ne soit pas présent.

Enregistrer des données pour la vue de liste afin de ne pas les recharger encore et encore pendant la reconstitution de fragment consiste à enregistrer ces données dans un membre statique d’une classe. Quelque chose comme

 class YourData{ public static List listViewData; } 

Et ensuite, à partir de l’adaptateur, commencez par charger les données à partir d’Internet ou de la firebase database locale, puis définissez les données récupérées sur ce membre statique comme suit:

  @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //Run the process to get data from database YourData.listViewData = dataResortingevedFromDatabase; } 

puis, dans votre méthode onResume, mettez à jour ces valeurs dans l’adaptateur, par exemple:

 @Override public void onResume() { super.onResume(); if(YourData.listViewData!=null){ yourListAdapater.setData = YourData.listViewData; listView.setAdapter(yourListAdapater); }else{ //run your method to get data from server } } 

Cela peut être utilisé pour enregistrer tout type de données pour une seule session