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 la 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 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:
class MyApp extends Application {
private String myState = /* complicated and slow initialization */;
public String getState(){
return myState;
}
}
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:
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();
...
}
}
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:
<application
android:name="my.application.MyApp"
android:icon="..."
android:label="...">
</application>
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:
- Incapacité à utiliser des classes abstraites ou d'interface;
- Incapacité de sous-classe;
- Couplage élevé à travers l'application (difficile à modifier);
- Difficile à tester (ne peut pas simuler / se moquer des tests unitaires);
- Difficile à paralléliser en cas d'état mutable (nécessite un verrouillage important);
et ajouter le mien:
- Contrat à vie imprécis et ingérable inadapté au développement Android (ou la plupart des autres);