592 votes

Android: Comment déclarer des variables globales?

Je suis entrain de créer une application qui nécessite une connexion. J'ai créé la principale et le nom de l'activité.

L'activité principale onCreate méthode, j'ai ajouté la condition suivante:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    ...

    loadSettings();
    if(strSessionString == null)
    {
        login();
    }
    ...
}

L' 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, c'est que le formulaire de connexion apparaît parfois deux fois ( login() méthode est appelée deux fois) et aussi quand le clavier de son téléphone diapositives le formulaire de connexion s'affiche à nouveau et je crois que le problème est la variable strSessionString.

Personne ne sait comment définir la variable globale afin d'éviter de connexion formulaire apparaissant après que l'utilisateur s'authentifie avec succès?

Merci!

952voto

sooniln Points 9909

J'ai écrit cette réponse de retour en '09 quand Android est relativement nouveau, et il n'était pas bien établie dans les zones de développement Android. J'ai ajouté une longue addendum au bas de ce post, d'aborder certains critiques, et les détails de la philosophie de désaccord que j'ai avec l'utilisation de Singletons plutôt que de sous-classement de l'Application. Lire à vos risques et périls.

RÉPONSE ORIGINALE À CETTE QUESTION:

Le problème plus général que vous rencontrez est de savoir comment économiser de l'état à travers plusieurs Activités et toutes les parties de votre application. Une variable statique (par exemple, un singleton) est une commune de Java manière d'y parvenir. J'ai trouvé, cependant, que d'une façon plus élégante dans Android est à associer votre état avec le contexte de l'Application.

Comme vous le savez, chaque Activité est aussi un Contexte qui est des informations sur son environnement d'exécution dans le sens le plus large. Votre application dispose également d'un contexte, et Android garantit qu'il existera aussi une instance unique dans votre application.

La façon de le faire est de créer votre propre sous-classe de android.app.L'Application, puis spécifiez la classe à la balise application dans votre manifeste. Maintenant Android va automatiquement créer une instance de cette classe et de le rendre disponible pour l'ensemble de votre application. Vous pouvez y accéder à partir de n'importe quel context à l'aide de l' Context.getApplicationContext() méthode (Activity fournit également une méthode getApplication() qui a exactement le même effet). Voici un exemple extrêmement simplifié, avec des mises en garde à suivre:

class MyApp extends Application {

  private String myState;

  public String getState(){
    return myState;
  }
  public void setState(String s){
    myState = s;
  }
}

class Blah extends Activity {

  @Override
  public void onCreate(Bundle b){
    ...
    MyApp appState = ((MyApp)getApplicationContext());
    String state = appState.getState();
    ...
  }
}

Cela a essentiellement le même effet que l'utilisation d'une variable statique ou d'un singleton, mais s'intègre assez bien dans l'existant Android-cadre. Notez que cela ne fonctionne pas à travers des processus (si votre application d'être l'un des rares qui a de multiples processus).

Quelque chose à noter à partir de l'exemple ci-dessus; supposons qu'il y a plutôt quelque chose comme:

class MyApp extends Application {

  private String myState = /* complicated and slow initialization */;

  public String getState(){
    return myState;
  }
}

Maintenant, cette lente d'initialisation (comme frapper disque, frapper réseau, rien de blocage, etc) sera exécuté à chaque fois qu'une Application est instancié! Vous pensez peut-être, eh bien, ce n'est qu'une fois le processus et que je vais devoir payer le coût de toute façon, non? Par exemple, comme Dianne Hackborn mentionne ci-dessous, il est tout à fait possible pour votre processus instancié -just - de gérer un contexte de diffusion de l'événement. Si votre diffusion de traitement n'a pas besoin de cet état, vous avez potentiellement tout fait toute une série de compliqué et lent opérations pour rien. Paresseux instanciation est le nom du jeu ici. La suite est un peu plus compliqué de l'aide de l'Application qui fait plus de sens pour rien, mais le plus simple d'utilisations:

class MyApp extends Application {

  private MyStateManager myStateManager = new MyStateManager();

  public MyStateManager getStateManager(){
    return myStateManager ;
  }
}

class MyStateManager {

  MyStateManager() {
    /* this should be fast */
  }

  String getState() {
    /* if necessary, perform blocking calls here */
    /* make sure to deal with any multithreading/synchronicity issues */

    ...

    return state;
  }
}

class Blah extends Activity {

  @Override
  public void onCreate(Bundle b){
    ...
    MyStateManager stateManager = ((MyApp)getApplicationContext()).getStateManager();
    String state = stateManager.getState();
    ...
  }
}

Tandis que je préfère Application de sous-classement à l'aide de singletons ici comme la solution la plus élégante, je préfère les développeurs à utiliser des singletons si vraiment nécessaire de ne pas penser à tous par le biais de la performance et le multithreading implications d'associer l'etat à la Demande de la sous-classe.

NOTE 1: Aussi comme anticafe commenté, afin de bien attacher votre Application substituer à votre demande une balise est nécessaire dans le fichier manifeste. Encore une fois, voir le Android docs pour plus d'info. Un exemple:

<application
     android:name="my.application.MyApp" 
     android:icon="..."
     android:label="...">
</application>

NOTE 2: user608578 demande ci-dessous comment cela fonctionne avec la gestion native de l'objet de cycles de vie. Je ne suis pas à la vitesse sur l'utilisation de code natif d'Android dans le moindre, et je ne suis pas qualifié pour répondre à comment cela pourrait interagir avec ma solution. Si quelqu'un a une réponse à cela, je suis prêt pour eux de crédit et de mettre les informations dans ce post, pour un maximum de visibilité.

ADDENDUM:

Comme certains l'ont noté, ce n'est pas une solution pour persistants de l'état, quelque chose que je devrait peut-être l'ai souligné plus dans la réponse originale à cette question. I. e. ce n'est pas destiné à être une solution pour économiser de l'utilisateur ou d'autres informations qui sont destinées à être conservées à travers l'application des durées de vie. Ainsi, je considère que la plupart des critiques ci-dessous relatifs aux Applications d'être tué à tout moment, etc..., discutable, que rien de ce que jamais besoin d'être enregistrées sur le disque ne doivent pas être stockées au moyen d'une Application de sous-classe. Il est destiné à être une solution pour le stockage temporaire, facilement ré-creatable l'état de l'application (si un utilisateur est connecté, par exemple) et des composants qui sont en instance unique (application gestionnaire de réseau par exemple) (PAS de singleton!) dans la nature.

Dayerman a été assez aimable pour un point intéressant de la conversation avec Reto Meier et Dianne Hackborn dans lequel l'utilisation de l'Application sous-classes est déconseillée au profit de Singleton modèles. Somatik également souligné quelque chose de cette nature plus tôt, même si je ne l'avais pas vu à l'époque. En raison de Reto et de Diane rôles dans le maintien de la plate-forme Android, je ne peux pas en toute bonne foi vous recommandons d'ignorer leurs conseils. Ce qu'ils disent, va. Je tiens à être en désaccord avec les opinions, exprimées en ce qui concerne préférant Singleton sur l'Application des sous-classes. Dans mon désaccord, je vais être en faisant usage de concepts mieux expliqué dans ce StackExchange explication du modèle de conception Singleton, de sorte que je n'ai pas à définir les termes de cette réponse. J'encourage vivement à parcourir le lien avant de continuer. Point par Point:

Dianne unis, "Il n'y a pas de raison de la sous-classe de l'Application. Il n'est pas différent que de faire un singleton..." Cette première affirmation est incorrecte. Il y a deux raisons principales à cela. 1) La classe d'Application fournit une meilleure garantie à vie pour un développeur de l'application; c'est la garantie d'avoir la durée de vie de l'application. Un singleton n'est pas EXPLICITEMENT liée à la durée de vie de l'application (bien qu'il soit efficace). Cela peut être un non-problème pour la moyenne de votre développeur de l'application, mais je dirais que c'est exactement le type de contrat, l'API Android devrait offrir, et il offre beaucoup plus de souplesse pour le système Android ainsi, en réduisant au minimum la durée de vie des données associées. 2) La classe d'Application fournit le développeur de l'application avec une instance unique titulaire de l'état, ce qui est très différent d'un Singleton titulaire de l'etat. Pour une liste des différences, voir le Singleton explication lien ci-dessus.

Dianne continue, "...juste probablement être quelque chose que vous regrettez dans l'avenir que vous trouvez votre Demande objet de devenir ce grand emmêlés de ce qui devrait être indépendante de l'application de la logique." Ce n'est certainement pas faux, mais ce n'est pas une raison pour le choix de Singleton, sur Demande de la sous-classe. Aucun de Diane les arguments de la raison que l'utilisation d'un Singleton est mieux qu'une Application de la sous-classe, tout ce qu'elle tente d'établir, c'est que l'utilisation d'un Singleton n'est pas pire qu'une Application de la sous-classe, qui je crois est faux.

Elle continue, "Et cela conduit plus naturellement à la façon dont vous devez gérer ces choses-de l'initialisation sur la demande." C'est ignorer le fait qu'il n'y a aucune raison que vous ne pouvez pas initialiser sur demande à l'aide d'une Application de sous-classe. Il n'y a pas de différence.

Dianne se termine avec "Le cadre lui-même a des tonnes et des tonnes de singletons pour tous les petits de données partagée qu'il tient pour l'application, comme les caches de chargé de ressources, de piscines, d'objets, etc. Il fonctionne très bien." Je ne prétends pas que l'utilisation de Singletons ne peut pas fonctionner correctement ou ne sont pas une alternative légitime. J'affirme que les Singletons ne fournissent pas aussi forte un contrat avec l'Android système, en utilisant une Application de sous-classe, et, de plus, à l'aide de Singletons généralement des points rigides de conception, ce qui n'est pas facilement modifiable, et conduit à de nombreux problèmes sur la route. À mon humble avis, le fort de contrat de l'API Android offre aux développeurs d'applications est l'un des plus attrayant et agréable aspects de la programmation avec Android, et a aidé à mener à début développeur qui a conduit à l'adoption de la plate-forme Android pour le succès qu'il a aujourd'hui. Ce qui suggère à l'aide de Singletons est implicitement en s'éloignant d'une forte API contrat, et à mon avis, affaiblit le Android-cadre.

Dianne a commenté ci-dessous, en mentionnant un inconvénient à l'utilisation de l'Application sous-classes, ils peuvent encourager ou de le rendre plus facile d'écrire moins de code de performance. Cela est très vrai, et j'ai édité cette réponse à souligner l'importance de tenir compte de la perf ici, et de prendre la bonne approche si vous utilisez une Application de sous-classement. Comme Dianne unis, il est important de se rappeler que votre classe d'Application sera instancié à chaque fois que votre processus est chargé (peut être à plusieurs reprises à la fois si votre application s'exécute dans plusieurs processus!) même si le processus n'est en cours de chargement pour un arrière-plan de diffusion de l'événement. Il est donc important d'utiliser la classe d'Application plus comme un référentiel pour les pointeurs partagés composants de votre application plutôt que comme un lieu pour faire le traitement!

Je vous laisse avec la liste suivante des inconvénients pour les Singletons, comme volés à partir de l'StackExchange lien:

  • De l'incapacité à utiliser abstraite ou une interface de classes;
  • L'incapacité de la sous-classe;
  • Haut de couplage à travers l'application (difficile de les modifier);
  • Difficile à tester (pas de faux/fantaisie dans les tests);
  • Difficile de paralléliser dans le cas de la mutable état (nécessite de verrouillage complète);

et d'ajouter ma propre:

  • Pas clair et ingérable durée de vie du contrat inadapté pour Android (ou la plupart des autres) le développement;

153voto

ebuprofen Points 1299

Créer de la présente sous-classe

public class MyApp extends Application {
  String foo;
}

Dans le AndroidManifest.xml ajouter android:name

Exemple

<application android:name=".MyApp" 
       android:icon="@drawable/icon" 
       android:label="@string/app_name">

142voto

Arhimed Points 18116

L'suggéré par Soonil façon de garder un état de l'application est bonne, mais il a un point faible - il y a des cas lors de l'OS tue l'ensemble du processus de demande. Voici la documentation de ce Processus et cycles de vie.

Considérons un cas de votre application passe en arrière-plan parce que quelqu'un vous appelle sur un Téléphone application est au premier plan maintenant). Dans ce cas, et sous certaines conditions (vérifier le lien ci-dessus pour ce qu'ils pourraient l'être), l'OS peut tuer votre processus de demande, y compris l' Application sous-classe de l'instance. En conséquence, l'état est perdu. Lorsque, plus tard, vous revenez à la demande, alors le système d'exploitation sera de restaurer son activité pile et Application sous-classe de l'instance, cependant l' myState champ sera null.

Autant que je sache, le seul moyen de garantir, dans l'état de la sécurité est d'utiliser toute sorte de persistance de l'état, par exemple à l'aide d'un privé pour le fichier de l'application ou de l' SharedPrefernces (il finalement utilise un privé pour l'application fichier à l'intérieur du système de fichiers).

26voto

Gimbl Points 748

Juste une remarque ..

ajouter:

android:name=".Globals"

ou tout ce que vous avez nommé votre sous-classe de l' existant, <application> balise. J'ai continué d'essayer d'ajouter un autre <application> balise pour le manifeste et une exception.

13voto

Mike Brown Points 131

Je ne pouvais pas trouver comment spécifier la balise application, soit, mais après beaucoup de recherches sur Google, il est devenu évident, à partir du fichier manifest docs: utiliser android:name, en plus de la valeur par défaut de l'icône et l'étiquette à l'application stanza.

android:name Le nom complet de l'Application de la sous-classe mis en œuvre pour l'application. Lors de l'application au démarrage du processus, cette classe est instanciée avant tout les composants de l'application.

La sous-classe est facultatif; la plupart des applications n'en a pas besoin. En l'absence d'une sous-classe, Android utilise une instance de la base de la classe d'Application.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X