Singletons vs. Contexto de la aplicación en Android?

Recordando esta publicación enumerando varios problemas del uso de singletons y habiendo visto varios ejemplos de aplicaciones de Android usando el patrón singleton, me pregunto si es una buena idea usar Singletons en lugar de instancias individuales compartidas a través del estado de la aplicación global (subclase android.os.Application y obtenerlo) a través de context.getApplication ()).

¿Qué ventajas / desventajas tendrán ambos mecanismos?

Para ser sincero, espero la misma respuesta en este post Singleton pattern with web application, ¡No es una buena idea! pero aplicado a Android. ¿Estoy en lo correcto? ¿Qué es diferente en DalvikVM de lo contrario?

EDITAR: Me gustaría tener opiniones sobre varios aspectos involucrados:

  • Sincronización
  • Reusabilidad
  • Pruebas

Estoy muy en desacuerdo con la respuesta de Dianne Hackborn. Poco a poco, estamos eliminando todos los elementos sueltos de nuestro proyecto a favor de objetos livianos que se pueden volver a crear cuando realmente los necesite.

Los singletons son una pesadilla para las pruebas y, si se inicializan lentamente, introducirán el “indeterminismo de estado” con efectos secundarios sutiles (que pueden surgir repentinamente al mover las llamadas a getInstance() de un scope a otro). La visibilidad se ha mencionado como otro problema, y ​​como los singleton implican un acceso “global” (= aleatorio) al estado compartido, pueden surgir errores sutiles cuando no se sincronizan correctamente en las aplicaciones concurrentes.

Lo considero un antipatrón, es un estilo malo orientado a objetos que esencialmente equivale a mantener el estado global.

Para volver a tu pregunta:

Aunque el contexto de la aplicación se puede considerar como un singleton, está gestionado por el marco y tiene un ciclo de vida bien definido, scope y ruta de acceso. Por lo tanto, creo que si necesita administrar el estado global de la aplicación, debería ir aquí, en ninguna otra parte. Para cualquier otra cosa, reconsidere si realmente necesita un objeto singleton, o si también sería posible reescribir su clase singleton para, en su lugar, crear instancias de objetos pequeños y efímeros que realicen la tarea en cuestión.

Recomiendo mucho singletons. Si tiene un singleton que necesita un contexto, tenga:

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

Prefiero Singletons a Application porque ayuda a mantener una aplicación mucho más organizada y modular: en lugar de tener un solo lugar donde se necesite mantener todo su estado global en toda la aplicación, cada pieza separada puede encargarse sola. También es bueno el hecho de que los singletons se inicialicen de forma lenta (a pedido) en lugar de guiarlo por el camino de hacer toda la inicialización por adelantado en Application.onCreate ().

No hay nada intrínsecamente incorrecto con el uso de singletons. Simplemente úselos correctamente, cuando tenga sentido. El framework Android en realidad tiene muchos de ellos, para mantener cachés por proceso de recursos cargados y otras cosas similares.

También para aplicaciones simples, el multihilo no se convierte en un problema con los singletons, ya que por diseño todas las devoluciones de llamada estándar a la aplicación se envían en el hilo principal del proceso para que no ocurra el multi-threading a menos que lo introduzcas explícitamente a través de hilos o implícitamente mediante la publicación de un proveedor de contenido o servicio de IBinder a otros procesos.

Solo piensa en lo que estás haciendo. 🙂

De: Desarrollador> referencia – Aplicación

Normalmente no hay necesidad de subclasificar la aplicación. En la mayoría de las situaciones, los singleton estáticos pueden proporcionar la misma funcionalidad de una manera más modular. Si su singleton necesita un contexto global (por ejemplo, para registrar receptores de difusión), la función para recuperarlo puede tener un Contexto que internamente utiliza Context.getApplicationContext () cuando construye el singleton por primera vez.

Tuve el mismo problema: ¿Singleton o hacer una subclase de android.os.Application?

Primero probé con Singleton pero mi aplicación en algún momento hace una llamada al navegador

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

y el problema es que, si el teléfono no tiene suficiente memoria, la mayoría de sus clases (incluso Singletons) se limpian para obtener algo de memoria, por lo que, cuando regresaba del navegador a mi aplicación, se bloqueaba cada vez.

Solución: coloque los datos necesarios dentro de una subclase de la clase de Aplicación.

La aplicación no es lo mismo que Singleton. Las razones son:

  1. El método de la aplicación (como onCreate) se llama en el hilo de la interfaz de usuario;
  2. el método de Singleton se puede invocar en cualquier hilo;
  3. En el método “onCreate” de la Aplicación, puede instanciar Handler;
  4. Si el singleton se ejecuta en subproceso no-ui, no podría instanciar Handler;
  5. La aplicación tiene la capacidad de administrar el ciclo de vida de las actividades en la aplicación. Tiene el método “registerActivityLifecycleCallbacks”. Pero los singletons no tienen la capacidad.

Considere ambos al mismo tiempo:

  • tener objetos singleton como instancias estáticas dentro de las clases.
  • tener una clase común (Contexto) que devuelve las instancias singleton para todos los objetos singelton en su aplicación, lo que tiene la ventaja de que los nombres de los métodos en Contexto tendrán sentido, por ejemplo: context.getLoggedinUser () en lugar de User.getInstance ().

Además, sugiero que expanda su Contexto para incluir no solo acceso a objetos únicos, sino algunas funcionalidades a las que se debe acceder globalmente, como por ejemplo: context.logOffUser (), context.readSavedData (), etc. Probablemente cambie el nombre del Contexto a Fachada tendría sentido entonces.

En realidad son lo mismo. Hay una diferencia que puedo ver. Con la clase de aplicación puede inicializar sus variables en Application.onCreate () y destruirlas en Application.onTerminate (). Con Singleton tienes que confiar en que VM inicialice y destruya la estática.

Mis 2 centavos:

Noté que algunos campos únicos / estáticos fueron reseteados cuando mi actividad fue destruida. Me di cuenta de esto en algunos dispositivos de gama baja 2.3.

Mi caso fue muy simple: solo tengo un archivo privado “init_done” y un método estático “init” al que llamé desde activity.onCreate (). Observé que el método init se estaba volviendo a ejecutar en alguna recreación de la actividad.

Si bien no puedo probar mi afirmación, puede estar relacionada con CUÁNDO se creó / usó la clase / singleton primero. Cuando la actividad se destruye / recicla, parece que todas las clases a las que solo se refiere esta actividad también se reciclan.

Moví mi instancia de singleton a una sub clase de aplicación. Los accedo desde la instancia de la aplicación. y, desde entonces, no se dio cuenta del problema nuevamente.

Espero que esto pueda ayudar a alguien.

De la boca del caballo proverbial …

Al desarrollar su aplicación, puede que sea necesario compartir datos, contextos o servicios de forma global en su aplicación. Por ejemplo, si su aplicación tiene datos de sesión, como el usuario actualmente conectado, es probable que desee exponer esta información. En Android, el patrón para resolver este problema es hacer que su instancia de Android.app.Application sea propietaria de todos los datos globales, y luego trate su instancia de aplicación como singleton con accesos estáticos a los diversos datos y servicios.

Al escribir una aplicación para Android, tiene la garantía de que solo tendrá una instancia de la clase android.app.Application, por lo que es seguro (y recomendado por el equipo de Google Android) tratarlo como singleton. Es decir, puede agregar de manera segura un método getInstance () estático a la implementación de su Aplicación. Al igual que:

 public class AndroidApplication extends Application { private static AndroidApplication sInstance; public static AndroidApplication getInstance(){ return sInstance; } @Override public void onCreate() { super.onCreate(); sInstance = this; } } 

Mi actividad llama a finish () (lo que no hace que termine de inmediato, pero lo hará eventualmente) y llama a Google Street Viewer. Cuando lo depuro en Eclipse, mi conexión a la aplicación se interrumpe cuando se llama a Street Viewer, que entiendo como la aplicación (completa) que se cierra, supuestamente para liberar memoria (como una sola actividad que se termina no debería causar este comportamiento) . Sin embargo, puedo guardar el estado en un paquete a través de onSaveInstanceState () y restaurarlo en el método onCreate () de la siguiente actividad en la stack. Ya sea mediante el uso de una aplicación estática de singleton o subclases, enfrento el estado de cierre y pérdida de la aplicación (a menos que lo guarde en un paquete). Entonces, según mi experiencia, son lo mismo con respecto a la preservación del estado. Noté que la conexión se pierde en Android 4.1.2 y 4.2.2 pero no en 4.0.7 o 3.2.4, lo que a mi entender sugiere que el mecanismo de recuperación de memoria ha cambiado en algún momento.