Utilisation de la classe Application Android pour conserver les données

112

Je travaille sur une application Android assez complexe qui nécessite une assez grande quantité de données sur l'application (je dirais un total d'environ 500 Ko - est-ce grand pour un appareil mobile?). D'après ce que je peux dire, tout changement d'orientation dans l'application (dans l'activité, pour être plus précis) provoque une destruction complète et une recréation de l'activité. D'après mes conclusions, la classe Application n'a pas le même cycle de vie (c'est-à-dire qu'elle est, à toutes fins utiles, toujours instanciée). Est-il judicieux de stocker les informations d'état à l'intérieur de la classe d'application, puis de les référencer à partir de l'activité, ou n'est-ce généralement pas la méthode «acceptable» en raison des contraintes de mémoire sur les appareils mobiles? J'apprécie vraiment tout conseil sur ce sujet. Merci!

Dave
la source
8
Gardez simplement à l'esprit que les données de votre application peuvent toujours être supprimées si votre application passe en arrière-plan, ce n'est donc pas une solution aux données persistantes que vous souhaitez toujours pouvoir récupérer. Cela sert simplement de méthode pour ne pas avoir à recréer des objets coûteux aussi souvent.
Cheryl Simon
2
Mayra; Je ne pense pas que l'application soit "généralement" supprimée (bien que, comme quelqu'un le souligne plus tard dans ce fil, elle "peut" l'être). Je vais probablement adopter une approche "hybride" d'utilisation de l'application pour stocker et charger les données, mais utiliser ensuite l'attribut "android: orientation" sur l'activité dans le fichier manifeste pour remplacer le comportement normal de démolir et reconstruire l'activité. Tout cela, bien sûr, suppose que l'application peut déterminer "quand" elle est détruite afin que les données puissent être conservées.
Dave

Réponses:

134

Je ne pense pas que 500kb sera un si gros problème.

Ce que vous avez décrit est exactement comment j'ai abordé mon problème de perte de données dans une activité. J'ai créé un singleton global dans la classe Application et j'ai pu y accéder à partir des activités que j'ai utilisées.

Vous pouvez transmettre des données dans un Global Singleton si elles doivent être beaucoup utilisées.

public class YourApplication extends Application 
{     
     public SomeDataClass data = new SomeDataClass();
}

Puis appelez-le dans n'importe quelle activité en:

YourApplication appState = ((YourApplication)this.getApplication());
appState.data.UseAGetterOrSetterHere(); // Do whatever you need to with the data here.

J'en discute ici dans mon article de blog , sous la section «Global Singleton».

Bryan Denny
la source
1
Malheureusement, l'article de blog en question n'est plus disponible à cette adresse.
mikebabcock
1
J'ai déplacé des choses sur mon site. Jusqu'à ce qu'il soit corrigé, vous pouvez le trouver sur archive.org ici: web.archive.org/web/20130818035631/http
Bryan Denny
1
Je sais que c'est un ancien message mais je viens de tomber sur un problème que cela pourrait résoudre, mais cette classe doit être décrite dans le manifeste, non? Je ne peux pas accéder à la classe, alors j'ai l'impression que c'est ce qui me manque ...
Ziv Kesten
1
@ZivKesten Que diriez-vous d'ajouter l'attribut name = à la balise d'application dans le manifeste?
MikeC
@mgc merci ça fait un moment, et oui c'est comme ça que j'ai finalement réussi, j'ai également créé des instances de cette classe là où j'en avais besoin en lui donnant le getApplicationContext () avec un casting pour cette classe
Ziv Kesten
57

Ceux qui comptent sur l' Applicationexemple se trompent. Au début, il peut sembler que le Applicationexiste aussi longtemps que l'ensemble du processus d'application existe, mais il s'agit d'une hypothèse incorrecte.

Le système d'exploitation peut tuer des processus si nécessaire. Tous les processus sont divisés en 5 niveaux de "killability" spécifiés dans la doc .

Ainsi, par exemple, si votre application passe en arrière-plan parce que l'utilisateur répond à un appel entrant, alors en fonction de l'état de la RAM, le système d'exploitation peut (ou non) tuer votre processus (détruisant l' Applicationinstance dans le processus) .

Je pense qu'une meilleure approche serait de conserver vos données dans un fichier de stockage interne , puis de le lire lorsque votre activité reprend.

METTRE À JOUR:

J'ai reçu de nombreux retours négatifs, il est donc temps d'ajouter une clarification. :) Eh bien, au départ, j'ai vraiment utilisé une fausse hypothèse selon laquelle l'état est vraiment important pour l'application. Cependant, si votre application est OK et que parfois l'état est perdu (il peut s'agir de certaines images qui seront simplement relues / téléchargées à nouveau), alors il est tout à fait OK de la conserver en tant que membre de Application.

Vit Khudenko
la source
14
Si l'application est supprimée, qui s'en soucie, n'est-ce pas? L'application est partie. Si je comprends bien, Android récupérera les processus qui contiennent de la mémoire comme les activités. Si le processus contenant l'application est tué (si Android le fait même?), C'est essentiellement comme tuer l'application. L'utilisateur devra relancer l'application et, à ce stade, qui s'en soucie? C'est une nouvelle instance de l'application.
Andrew
14
Ce fut une surprise imprudente pour nous en production. Croyez-moi, Android tue les processus, cela dépend juste de l'état de la RAM et d'autres facteurs décrits dans la documentation. C'était un cauchemar pour nous donc je partage juste ma vraie expérience. Eh bien, nous n'avions pas cela sur les émulateurs, mais dans le monde réel, certains appareils sont `` surchargés '' d'applications, donc tuer un processus d'arrière-plan est une situation normale. Oui, si l'utilisateur décide ensuite de mettre l'application au premier plan, le système d'exploitation restaure sa pile, y compris l' Applicationinstance, mais il n'y aura pas de données statiques sur lesquelles vous comptez à moins que vous ne les ayez persistées.
Vit Khudenko
2
Je pense que je vais probablement utiliser une approche hybride. Je connaissais déjà l'astuce manifeste pour annuler le changement d'orientation (qui a d'autres avantages). Puisque l'application est un jeu, je ne suis pas sûr que la persistance des données entre les lancements soit suffisamment "importante"; bien que ce ne soit probablement pas terriblement difficile car la plupart des données peuvent être sérialisées (bien que je ne voudrais pas sérialiser et désérialiser entre chaque changement d'orientation). J'apprécie vraiment la contribution. Je ne dirais pas que ceux qui dépendent de l'instance de l'application sont «faux». Cela dépend beaucoup de l'application :).
Dave
1
@Arhimed, vous généralisez trop votre réponse. Et suggérant une approche étroite basée sur votre hypothèse. Hypothèse fausse: les données contenues dans les variables statiques doivent être conservées entre les sessions de l'application. Il peut y avoir de nombreux cas d'utilisation où les données sont insignifiantes et n'ont pas besoin d'être conservées immédiatement.
Mandar Limaye
2
J'ai environ 1 Mo de données avec une structure compliquée. La sérialisation / désérialisation peut me coûter jusqu'à 2-3 secondes lorsque l'appareil est surchargé de travail. L'idée de sauvegarder / charger entre les activités coûte trop de temps. J'utilise l'application comme stockage. Bien sûr, ma classe de données stockée dans l'instance d'application a un contrôle sur chaque métode - les données sont-elles toujours vivantes ou doivent être chargées. Donc Dave doit: 1. fournir des fonctions de chargement / sauvegarde 2. conserver les données dans l'application. 3. Triple logique de contrôle pour accéder aux données.
Kostadin
6

Si vous souhaitez accéder au "Global Singleton" en dehors d'une activité et que vous ne souhaitez pas passer Contextpar tous les objets impliqués pour obtenir le singleton, vous pouvez simplement définir un attribut statique dans votre classe d'application, qui contient la référence à lui-même. Initialisez simplement l'attribut dans la onCreate()méthode.

Par exemple:

public class ApplicationController extends Application {
    private static ApplicationController _appCtrl;

    public static ApplicationController getAppCtrl()
    {
         return _appCtrl;
    }
}

Parce que les sous-classes de Application peuvent également obtenir les ressources, vous pouvez y accéder simplement lorsque vous définissez une méthode statique, qui les renvoie, comme:

public static Resources getAppResources()
{
    return _appCtrl.getResources();
}

Mais soyez très prudent lorsque vous passez des références de contexte pour éviter les fuites de mémoire .

saxos
la source
6
Vous avez oublié de noter que vous devez ajouter l'attribut xml android: name = ". ApplicationController" à la balise d'application dans votre manifeste pour que la classe soit instanciée.
eggie5
Vous n'avez pas vraiment besoin de vous étendre Applicationpour ce faire. Vous pouvez déclarer une variable membre statique dans n'importe quelle classe pour ce faire.
David Wasser
2

Dave, de quel genre de données s'agit-il? Si ce sont des données générales qui concernent l'application dans son ensemble (exemple: données utilisateur), étendez la classe Application et stockez-la là. Si les données concernent l'activité, vous devez utiliser les gestionnaires onSaveInstanceState et onRestoreInstanceState pour conserver les données lors de la rotation de l'écran.

Andrew
la source
Et si les données sont vraiment volumineuses à stocker dans un colis? Voici ce que j'obtiens: android.os.TransactionTooLargeException: taille du colis de données 838396 octets
Arjun Issar
1

Vous pouvez en fait remplacer la fonctionnalité d'orientation pour vous assurer que votre activité n'est pas détruite et recréée. Regardez ici .

Grantland à mâcher
la source
16
Vous pouvez faire beaucoup de choses. Cela ne veut pas dire que ce sont de bonnes idées. Ce n'est pas une bonne idée.
Andrew
Tester en modifiant l'orientation de l'écran est le moyen le plus simple de s'assurer que votre application fait ce qu'Android suppose qu'elle fait.
18446744073709551615
0

Vous pouvez créer une classe Application et enregistrer toutes vos données sur ces cals pour les utiliser n'importe où dans votre application.

Ashish Jaiswal
la source
0

Je sais que c'est la très vieille question, mais l'utilisation du ViewModel des composants jetpack est le meilleur moyen de préserver les données entre la rotation d'activité.

La classe ViewModel est conçue pour stocker et gérer les données liées à l'interface utilisateur de manière consciente du cycle de vie. La classe ViewModel permet aux données de survivre aux modifications de configuration telles que les rotations d'écran.

Dharmendra
la source