Je crée une application qui nécessite une connexion. J'ai créé l'activité principale et la connexion.
Dans la onCreate
méthode d' activité principale, j'ai ajouté la condition suivante:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
...
loadSettings();
if(strSessionString == null)
{
login();
}
...
}
La onActivityResult
méthode qui est exécutée lorsque le formulaire de connexion se termine ressemble à ceci:
@Override
public void onActivityResult(int requestCode,
int resultCode,
Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode)
{
case(SHOW_SUBACTICITY_LOGIN):
{
if(resultCode == Activity.RESULT_OK)
{
strSessionString = data.getStringExtra(Login.SESSIONSTRING);
connectionAvailable = true;
strUsername = data.getStringExtra(Login.USERNAME);
}
}
}
Le problème est que le formulaire de connexion apparaît parfois deux fois (la login()
méthode est appelée deux fois) et également lorsque le clavier du téléphone glisse, le formulaire de connexion apparaît à nouveau et je suppose que le problème est la variable strSessionString
.
Quelqu'un sait-il comment définir la variable globale afin d'éviter que le formulaire de connexion n'apparaisse après que l'utilisateur s'est déjà authentifié avec succès?
android
singleton
global-variables
state
Niko Gamulin
la source
la source
Réponses:
J'ai écrit cette réponse en '09 quand Android était relativement nouveau, et il y avait beaucoup de domaines mal établis dans le développement Android. J'ai ajouté un long addendum au bas de cet article, adressant certaines critiques et détaillant un désaccord philosophique que j'ai avec l'utilisation de Singletons plutôt que de sous-classer Application. Lisez-le à vos risques et périls.
RÉPONSE ORIGINALE:
Le problème plus général que vous rencontrez est de savoir comment enregistrer l'état sur plusieurs activités et toutes les parties de votre application. Une variable statique (par exemple, un singleton) est un moyen Java courant d'y parvenir. J'ai cependant constaté qu'une manière plus élégante dans Android consiste à associer votre état au contexte de l'application.
Comme vous le savez, chaque Activité est également un Contexte, qui est une information sur son environnement d'exécution au sens large. Votre application a également un contexte et Android garantit qu'elle existera en tant qu'instance unique dans votre application.
La façon de procéder consiste à créer votre propre sous-classe de android.app.Application , puis à spécifier cette classe dans la balise d'application de votre manifeste. Désormais, Android créera automatiquement une instance de cette classe et la rendra disponible pour l'ensemble de votre application. Vous pouvez y accéder à partir de tout en
context
utilisant laContext.getApplicationContext()
méthode (Activity
fournit également une méthodegetApplication()
qui a exactement le même effet). Voici un exemple extrêmement simplifié, avec des mises en garde à suivre:Cela a essentiellement le même effet que l'utilisation d'une variable statique ou singleton, mais s'intègre assez bien dans le cadre Android existant. Notez que cela ne fonctionnera pas entre les processus (si votre application est l'une des rares à avoir plusieurs processus).
Quelque chose à noter dans l'exemple ci-dessus; supposons que nous avions plutôt fait quelque chose comme:
Maintenant, cette lente initialisation (comme frapper le disque, frapper le réseau, tout ce qui bloque, etc.) sera effectuée chaque fois que l'application est instanciée! Vous pensez peut-être que ce n'est qu'une fois pour le processus et que je devrai quand même en payer le coût, non? Par exemple, comme Dianne Hackborn le mentionne ci-dessous, il est tout à fait possible que votre processus soit instancié - juste - pour gérer un événement de diffusion en arrière-plan. Si votre traitement de diffusion n'a pas besoin de cet état, vous venez potentiellement d'effectuer toute une série d'opérations compliquées et lentes pour rien. L'instanciation paresseuse est le nom du jeu ici. Ce qui suit est une façon légèrement plus compliquée d'utiliser Application qui a plus de sens pour tout sauf la plus simple des utilisations:
Bien que je préfère la sous-classe d'application à l'utilisation de singletons ici comme solution plus élégante, je préférerais que les développeurs utilisent des singletons si c'est vraiment nécessaire plutôt que de réfléchir du tout sur les performances et les implications multithreads de l'association de l'état à la sous-classe d'application.
REMARQUE 1: également comme anticafe a commenté, afin de lier correctement votre remplacement d'application à votre application, une balise est nécessaire dans le fichier manifeste. Encore une fois, consultez les documents Android pour plus d'informations. Un exemple:
REMARQUE 2: user608578 demande ci-dessous comment cela fonctionne avec la gestion des cycles de vie des objets natifs. Je ne suis pas du tout au courant de l'utilisation du code natif avec Android, et je ne suis pas qualifié pour répondre à la façon dont cela interagirait avec ma solution. Si quelqu'un a une réponse à cela, je suis prêt à lui attribuer le mérite et à mettre les informations dans ce message pour une visibilité maximale.
ADDENDA:
Comme certaines personnes l'ont noté, ce n'est pas une solution pour un état persistant , quelque chose que j'aurais peut-être dû souligner davantage dans la réponse originale. C'est-à-dire que ce n'est pas censé être une solution pour enregistrer l'utilisateur ou d'autres informations qui doivent être conservées pendant la durée de vie des applications. Ainsi, je considère que la plupart des critiques ci-dessous concernent les applications tuées à tout moment, etc. Il est censé être une solution pour stocker l'état d'application temporaire, facilement recréable (qu'un utilisateur soit connecté par exemple) et les composants qui sont de nature unique (gestionnaire de réseau d'application par exemple) ( PAS singleton!).
Dayerman a eu la gentillesse de signaler une conversation intéressante avec Reto Meier et Dianne Hackborn dans laquelle l'utilisation des sous-classes d'application est déconseillée en faveur des modèles Singleton. Somatik a également souligné quelque chose de cette nature plus tôt, même si je ne l'avais pas vu à l'époque. En raison des rôles de Reto et Dianne dans la maintenance de la plate-forme Android, je ne peux pas recommander de bonne foi d'ignorer leurs conseils. Ce qu'ils disent, va. Je ne suis pas d'accord avec les opinions exprimées concernant la préférence pour Singleton aux sous-classes d'application. Dans mon désaccord, je vais utiliser les concepts les mieux expliqués dans cette explication StackExchange du modèle de conception Singleton, de sorte que je n'ai pas à définir de termes dans cette réponse. J'encourage fortement à parcourir le lien avant de continuer. Point par point:
Dianne déclare: "Il n'y a aucune raison de sous-classer Application. Ce n'est pas différent que de faire un singleton ..." Cette première affirmation est incorrecte. Il y a deux raisons principales pour cela. 1) La classe Application offre une meilleure garantie à vie pour un développeur d'applications; il est garanti d'avoir la durée de vie de l'application. Un singleton n'est pas EXPLICITEMENT lié à la durée de vie de l'application (bien qu'il le soit effectivement). Cela peut ne pas être un problème pour votre développeur d'applications moyen, mais je dirais que c'est exactement le type de contrat que l'API Android devrait offrir, et il offre également beaucoup plus de flexibilité au système Android, en minimisant la durée de vie des applications associées. Les données. 2) La classe Application fournit au développeur d'application un seul titulaire d'instance pour l'état, ce qui est très différent d'un titulaire d'État Singleton. Pour une liste des différences, voir le lien d'explication Singleton ci-dessus.
Dianne poursuit: "... c'est probablement quelque chose que vous regretterez à l'avenir alors que vous trouvez que votre objet Application devient ce gros gâchis enchevêtré de ce qui devrait être une logique d'application indépendante." Ce n'est certainement pas incorrect, mais ce n'est pas une raison pour choisir Singleton plutôt que la sous-classe Application. Aucun des arguments de Diane ne fournit une raison pour laquelle l'utilisation d'un Singleton est meilleure qu'une sous-classe Application, tout ce qu'elle tente d'établir est que l'utilisation d'un Singleton n'est pas pire qu'une sous-classe Application, ce qui, à mon avis, est faux.
Elle poursuit: "Et cela conduit plus naturellement à la façon dont vous devriez gérer ces choses - en les initialisant à la demande." Cela ignore le fait qu'il n'y a aucune raison pour laquelle vous ne pouvez pas initialiser à la demande à l'aide d'une sous-classe d'application également. Encore une fois, il n'y a aucune différence.
Dianne termine avec "Le framework lui-même a des tonnes et des tonnes de singletons pour toutes les petites données partagées qu'il maintient pour l'application, telles que les caches de ressources chargées, les pools d'objets, etc. Il fonctionne très bien." Je ne dis pas que l'utilisation de Singletons ne peut pas fonctionner correctement ou n'est pas une alternative légitime. Je soutiens que les singletons ne fournissent pas un contrat aussi solide avec le système Android que l'utilisation d'une sous-classe d'application, et en outre que l'utilisation de singletons indique généralement une conception inflexible, qui n'est pas facilement modifiable, et conduit à de nombreux problèmes sur la route. À mon humble avis, le contrat solide que l'API Android offre aux applications de développement est l'un des aspects les plus attrayants et les plus agréables de la programmation avec Android, et a contribué à une adoption précoce par les développeurs, ce qui a conduit la plate-forme Android au succès qu'elle connaît aujourd'hui.
Dianne a également commenté ci-dessous, mentionnant un inconvénient supplémentaire à l'utilisation des sous-classes d'application, elles peuvent encourager ou faciliter l'écriture de code de performances inférieur. C'est très vrai, et j'ai édité cette réponse pour souligner l'importance de considérer la perf ici et d'adopter la bonne approche si vous utilisez le sous-classement d'application. Comme l'indique Dianne, il est important de se rappeler que votre classe Application sera instanciée à chaque fois que votre processus est chargé (pourrait être plusieurs fois à la fois si votre application s'exécute dans plusieurs processus!) Même si le processus n'est chargé que pour une diffusion en arrière-plan un événement. Il est donc important d'utiliser la classe Application plus comme référentiel pour les pointeurs vers les composants partagés de votre application plutôt que comme un endroit pour effectuer n'importe quel traitement!
Je vous laisse avec la liste suivante des inconvénients des Singletons, volés à partir du lien StackExchange précédent:
et ajouter le mien:
la source
Créer cette sous-classe
Dans AndroidManifest.xml, ajoutez android: nom
Exemple
la source
java.lang.IllegalAccessException: access to class is not allowed
La façon suggérée par Soonil de conserver un état pour l'application est bonne, mais elle a un point faible - il y a des cas où le système d'exploitation tue tout le processus de demande. Voici la documentation à ce sujet - Processus et cycles de vie .
Prenons un cas - votre application passe en arrière-plan parce que quelqu'un vous appelle (l'application Téléphone est maintenant au premier plan). Dans ce cas && sous d'autres conditions (vérifiez le lien ci-dessus pour ce qu'elles pourraient être), le système d'exploitation peut tuer votre processus de demande, y compris l'
Application
instance de sous - classe. En conséquence, l'État est perdu. Lorsque vous reviendrez ultérieurement à l'application, le système d'exploitation restaurera sa pile d'activité et sonApplication
instance de sous - classe, quel que soit lemyState
champnull
.AFAIK, le seul moyen de garantir la sécurité de l'État est d'utiliser toute sorte de persistance de l'État, par exemple en utilisant un privé pour le fichier d'application ou
SharedPrefernces
(il utilise finalement un privé pour le fichier d'application dans le système de fichiers interne).la source
SharedPreferences
; c'est comme ça que je l'ai vu faire. Je trouve étrange d'abuser du système de préférence pour l'état enregistré, mais cela fonctionne si bien que le problème ne devient qu'une question de terminologie.Juste une note ..
ajouter:
ou tout ce que vous avez nommé votre sous-classe à la balise existante
<application>
. J'ai continué à essayer d'ajouter une autre<application>
balise au manifeste et j'obtiendrais une exception.la source
Je n'ai pas non plus trouvé comment spécifier la balise d'application, mais après beaucoup de recherches sur Google, cela est devenu évident à partir des documents du fichier manifeste: utilisez android: name, en plus de l'icône et de l'étiquette par défaut dans la strophe d'application.
android: name Nom complet d'une sous-classe d'application implémentée pour l'application. Lorsque le processus d'application est démarré, cette classe est instanciée avant l'un des composants de l'application.
La sous-classe est facultative; la plupart des applications n'en auront pas besoin. En l'absence d'une sous-classe, Android utilise une instance de la classe Application de base.
la source
Qu'en est-il d'assurer la collecte de mémoire native avec de telles structures globales?
Les activités ont une
onPause/onDestroy()
méthode appelée destruction, mais la classe Application n'a pas d'équivalent. Quel mécanisme est recommandé pour garantir que les structures globales (en particulier celles contenant des références à la mémoire native) sont correctement récupérées lorsque l'application est supprimée ou que la pile de tâches est mise en arrière-plan?la source
Il vous suffit de définir un nom d'application comme ci-dessous qui fonctionnera:
la source
Comme il a été discuté ci-dessus, le système d'exploitation pourrait tuer l'APPLICATION sans aucune notification (il n'y a pas d'événement onDestroy), il n'y a donc aucun moyen de sauvegarder ces variables globales.
SharedPreferences pourrait être une solution SAUF si vous avez des variables STRUCTURÉES COMPLEXES (dans mon cas, j'avais un tableau d'entiers pour stocker les identifiants que l'utilisateur a déjà traités). Le problème avec les SharedPreferences est qu'il est difficile de stocker et de récupérer ces structures à chaque fois que les valeurs nécessaires.
Dans mon cas, j'avais un SERVICE en arrière-plan pour que je puisse déplacer ces variables là-bas et parce que le service a l'événement onDestroy, je pouvais enregistrer ces valeurs facilement.
la source
Si certaines variables sont stockées dans sqlite et que vous devez les utiliser dans la plupart des activités de votre application. alors l'application est peut-être le meilleur moyen d'y parvenir. Recherchez les variables de la base de données au démarrage de l'application et stockez-les dans un champ. Ensuite, vous pouvez utiliser ces variables dans vos activités.
Alors, trouvez le bon chemin, et il n'y a pas de meilleur moyen.
la source
Vous pouvez avoir un champ statique pour stocker ce type d'état. Ou mettez-le dans le bundle de ressources et restaurez-le à partir de là onCreate (Bundle savedInstanceState). Assurez-vous simplement de bien comprendre le cycle de vie géré par l'application Android (par exemple, pourquoi login () est appelé lors du changement d'orientation du clavier).
la source
NE N'UTILISEZ PAS une autre
<application>
balise dans le fichier manifeste. Faites simplement un changement dans la<application>
balise existante , ajoutez cette ligneandroid:name=".ApplicationName"
oùApplicationName
sera le nom de votre sous-classe (à utiliser pour stocker global) que vous êtes sur le point de créer.donc, enfin, votre balise ONE AND ONLY
<application>
dans le fichier manifeste devrait ressembler à ceci: -la source
vous pouvez utiliser Intents, Sqlite ou Shared Preferences. En ce qui concerne le stockage multimédia, comme les documents, les photos et les vidéos, vous pouvez créer les nouveaux fichiers à la place.
la source
Vous pouvez le faire en utilisant deux approches:
Utilisation des préférences partagées
Utilisation de la classe Application
Exemple:
Vous pouvez utiliser la classe ci-dessus pour implémenter la connexion dans votre MainActivity comme ci-dessous. Le code ressemblera à ceci:
Cette méthode fonctionnera pour le stockage temporaire. Vous ne savez vraiment pas quand le système d'exploitation va tuer l'application, à cause de la mémoire insuffisante. Lorsque votre application est en arrière-plan et que l'utilisateur navigue dans une autre application qui nécessite plus de mémoire pour s'exécuter, votre application sera supprimée car le système d'exploitation accorde plus de priorité aux processus de premier plan qu'à l'arrière-plan. Par conséquent, votre objet d'application sera nul avant la déconnexion de l'utilisateur. Par conséquent, pour cela, je recommande d'utiliser la deuxième méthode spécifiée ci-dessus.
Utilisation de préférences partagées.
la source
Le résultat de l'activité est appelé avant la reprise. Déplacez donc votre vérification de connexion à la reprise et votre deuxième connexion peut être bloquée une fois que l'activité secomd a renvoyé un résultat positif. Le CV est appelé à chaque fois donc il n'y a pas de soucis à ce qu'il ne soit pas appelé la première fois.
la source
L'approche du sous-classement a également été utilisée par le framework BARACUS. De mon point de vue application de sous- classement était destinée à fonctionner avec les cycles de vie d'Android; c'est ce que fait n'importe quel conteneur d'application. Au lieu d'avoir des globaux alors, j'enregistre des beans dans ce contexte et les laisse être injectés dans n'importe quelle classe gérable par le contexte. Chaque instance de bean injectée est en fait un singleton.
Voir cet exemple pour plus de détails
Pourquoi faire du travail manuel si vous pouvez en avoir tellement plus?
la source
la source
Vous pouvez créer une classe qui étend la
Application
classe, puis déclarer votre variable en tant que champ de cette classe et lui fournir une méthode getter.Et puis pour accéder à cette variable dans votre activité, utilisez ceci:
la source