web-dev-qa-db-fra.com

Singletons vs contexte d'application dans Android?

Rappelant ceci après avoir énuméré plusieurs problèmes liés à l'utilisation de singletons et après avoir vu plusieurs exemples d'applications Android utilisant un motif singleton, je me demande si c'est une bonne idée d'utiliser des singletons au lieu d'instances uniques partagées via état global de l'application (sous-classe Android.os.Application et obtention via context.getApplication ()).

Quels sont les avantages/inconvénients des deux mécanismes?

Pour être honnête, j'attends la même réponse dans cet article Motif Singleton avec application Web, pas une bonne idée! mais appliqué à Android. Ai-je raison? En quoi DalvikVM est-il différent?

EDIT: J'aimerais avoir des opinions sur plusieurs aspects:

  • Synchronisation
  • Réutilisabilité
  • Essai
360
mschonaker

Je suis très en désaccord avec la réponse de Dianne Hackborn. Nous retirons peu à peu tous les singletons de notre projet au profit d’objets légers et à la portée des tâches qui peuvent facilement être recréés lorsque vous en avez réellement besoin.

Les singletons sont un cauchemar pour les tests et, s'ils sont initialisés paresseusement, introduiront "indéterminisme d'état" avec des effets secondaires subtils (qui peuvent soudainement faire surface lors du déplacement d'appels vers getInstance() d'une portée à une autre). La visibilité a été mentionnée comme un autre problème et, puisque les singletons impliquent "global" (= random) l'accès à l'état partagé, des bogues subtils peuvent survenir lorsqu'ils ne sont pas correctement synchronisés dans des applications concurrentes.

Je le considère comme un anti-motif, c'est un mauvais style orienté objet qui revient essentiellement à maintenir un état global.

Pour revenir à votre question:

Bien que le contexte d'application puisse être considéré comme un singleton lui-même, il est géré par la structure et possède un cycle de vie bien défini , une portée et un chemin d'accès. Par conséquent, je pense que si vous avez besoin de gérer l'état global d'une application, il devrait aller ici, nulle part ailleurs. Pour toute autre chose, repensez si vous avez vraiment besoin d’un objet singleton, ou s’il serait également possible de réécrire votre classe singleton pour au lieu d’instancier un petit, bref. objets vécus qui effectuent la tâche à accomplir.

292
Matthias

Je recommande vivement les singletons. Si vous avez un singleton qui a besoin d'un contexte, ayez:

MySingleton.getInstance(Context c) {
    //
    // ... needing to create ...
    sInstance = new MySingleton(c.getApplicationContext());
}

Je préfère les singletons aux applications, car cela permet de garder une application beaucoup plus organisée et modulaire - au lieu d'avoir un emplacement où l'ensemble de votre état global doit être maintenu, chaque élément séparé peut prendre soin de lui-même. De plus, le fait que des singletons s’initialisent paresseusement (à la demande) au lieu de vous guider dans la procédure d’initialisation initiale dans Application.onCreate () est bon.

Il n'y a rien de mal intrinsèquement à utiliser des singletons. Il suffit de les utiliser correctement, quand cela a du sens. Le framework Android en contient beaucoup, ce qui lui permet de conserver des caches par processus de ressources chargées, entre autres.

Aussi, pour les applications simples, le multithreading ne devient pas un problème avec les singletons, car, de par sa conception, tous les rappels standard vers l'application sont envoyés sur le thread principal du processus. Ainsi, le multi-threading ne se produit que si vous l'introduisez explicitement par le biais de threads ou implicitement en publiant un fournisseur de contenu ou un service IBinder vers d’autres processus.

Pensez à ce que vous faites. :)

227
hackbod

De: Développeur> référence - Application

Il n’est normalement pas nécessaire de sous-classer Application. Dans la plupart des cas, les singletons statiques peuvent fournir les mêmes fonctionnalités de manière plus modulaire. Si votre singleton a besoin d'un contexte global (par exemple, pour enregistrer des récepteurs de diffusion), la fonction permettant de le récupérer peut se voir attribuer un contexte qui utilise en interne Context.getApplicationContext () lors de la première construction du singleton.

20
Somatik

J'ai eu le même problème: Singleton ou faire une sous-classe Android.os.Application?

J'ai d'abord essayé avec Singleton, mais mon application appelle à un moment donné le navigateur.

Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));

et le problème est que, si le combiné ne dispose pas de suffisamment de mémoire, la plupart de vos classes (même Singletons) sont nettoyées pour obtenir de la mémoire. Ainsi, lorsque vous revenez du navigateur à mon application, il se bloque à chaque fois.

Solution: placer les données nécessaires dans une sous-classe de la classe Application.

11
JoséMi

L'application n'est pas la même que celle du Singleton. Les raisons sont les suivantes:

  1. La méthode de l'application (telle que onCreate) est appelée dans le thread ui;
  2. la méthode de singleton peut être appelée dans n'importe quel thread.
  3. Dans la méthode "onCreate" de Application, vous pouvez instancier Handler;
  4. Si le singleton est exécuté dans un thread no-ui, vous ne pouvez pas instancier Handler;
  5. L'application a la capacité de gérer le cycle de vie des activités dans l'application.Elle a la méthode "registerActivityLifecycleCallbacks" .Mais les singletons n'ont pas la capacité.
10
sunhang

Considérez les deux en même temps:

  • avoir des objets singleton en tant qu'instances statiques à l'intérieur des classes.
  • avoir une classe commune (Context) qui renvoie les instances singleton pour tous les objets singelton de votre application, ce qui présente l'avantage que les noms de méthode dans Context auront un sens, par exemple: context.getLoggedinUser () au lieu de User.getInstance ().

De plus, je vous suggère d’élargir votre contexte pour inclure non seulement l’accès aux objets singleton, mais également certaines fonctionnalités qui doivent être accessibles de manière globale, comme par exemple: context.logOffUser (), context.readSavedData (), etc. Renommant probablement le contexte en La façade aurait alors un sens.

5
adranale

Ils sont en fait les mêmes. Il y a une différence que je peux voir. Avec Application class, vous pouvez initialiser vos variables dans Application.onCreate () et les détruire dans Application.onTerminate (). Avec singleton, vous devez compter VM pour initialiser et détruire la statique.

4
Fedor

De la bouche proverbiale du cheval ...

Lors du développement de votre application, il peut s'avérer nécessaire de partager des données, du contexte ou des services de manière globale sur l'ensemble de votre application. Par exemple, si votre application contient des données de session, telles que l'utilisateur actuellement connecté, vous souhaiterez probablement exposer ces informations. Sous Android, la solution à ce problème consiste à laisser votre instance Android.app.Application posséder toutes les données globales, puis à traiter votre instance Application en tant que singleton avec des accesseurs statiques aux divers services et données.

Lorsque vous écrivez une application Android, vous ne pouvez disposer que d'une seule instance de la classe Android.app.Application. Il est donc prudent (et recommandé par l'équipe de Google Android) de traiter comme un singleton. En d’autres termes, vous pouvez ajouter en toute sécurité une méthode statique getInstance () à votre implémentation d’Application. Ainsi:

public class AndroidApplication extends Application {

    private static AndroidApplication sInstance;

    public static AndroidApplication getInstance(){
        return sInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sInstance = this;
    }
}
3
RMcGuigan

Mes 2 centimes:

J'ai remarqué que certains champs singleton/static ont été réinitialisés lorsque mon activité a été détruite. J'ai remarqué cela sur certains périphériques bas de gamme 2.3.

Mon cas était très simple: je viens d'avoir un fichier privé "init_done" et une méthode statique "init" que j'ai appelée depuis activity.onCreate (). Je remarque que la méthode init était en train de se ré-exécuter lors de la recréation de l'activité.

Bien que je ne puisse pas prouver mon affirmation, cela peut être lié au QUAND le singleton/la classe a été créé/utilisé en premier. Lorsque l'activité est détruite/recyclée, il semble que toutes les classes référencées uniquement par cette activité sont également recyclées.

J'ai déplacé mon instance de singleton dans une sous-classe d'application. Je les accède à partir de l'instance d'application. et, depuis lors, je n'ai plus remarqué le problème.

J'espère que cela peut aider quelqu'un.

3
Christ

Mon activité appelle finish () (ce qui ne la fait pas finir immédiatement, mais le sera éventuellement) et appelle Google Street Viewer. Lorsque je le débogue sur Eclipse, ma connexion à l'application est interrompue lorsque Street Viewer est appelé, ce qui, d'après ce que je comprends, signifie que l'application (entière) est fermée, afin de libérer de la mémoire (une activité unique ne devrait pas provoquer ce comportement). . Néanmoins, je suis capable de sauvegarder un état dans un Bundle via onSaveInstanceState () et de le restaurer dans la méthode onCreate () de la prochaine activité de la pile. Soit en utilisant un singleton statique ou une application de sous-classement, je suis confronté à la fermeture et à la perte de l’application (sauf si je l’enregistre dans un Bundle). Donc, d'après mon expérience, ils sont les mêmes en ce qui concerne la préservation de l'État. J'ai remarqué que la connexion est perdue dans Android 4.1.2 et 4.2.2, mais pas dans 4.0.7 ou 3.2.4, ce qui, à mon sens, suggère que le mécanisme de récupération de mémoire a changé à un moment donné.

2
Piovezan