Escribí esta respuesta en 2009 cuando Android era relativamente nuevo, y había muchas áreas no bien establecidas en el desarrollo de Android. He agregado un largo apéndice al final de esta publicación, que aborda algunas críticas y detalla un desacuerdo filosófico que tengo con el uso de Singletons en lugar de subclasificar la Aplicación. Léalo bajo su propio riesgo.
RESPUESTA ORIGINAL:
El problema más general que encuentra es cómo guardar el estado en varias Actividades y todas las partes de su aplicación. Una variable estática (por ejemplo, un singleton) es una forma común de Java para lograr esto. Sin embargo, he descubierto que una forma más elegante en Android es asociar su estado con el contexto de la Aplicación.
Como saben, cada Actividad es también un Contexto, que es información sobre su entorno de ejecución en el sentido más amplio. Su aplicación también tiene un contexto, y Android garantiza que existirá como una instancia única en su aplicación.
La forma de hacerlo es crear su propia subclase de android.app.Application , y luego especificar esa clase en la etiqueta de la aplicación en su manifiesto. Ahora Android creará automáticamente una instancia de esa clase y la pondrá a disposición de toda su aplicación. Puede acceder a él desde cualquier lugar context
utilizando el Context.getApplicationContext()
método ( Activity
también proporciona un método getApplication()
que tiene exactamente el mismo efecto). El siguiente es un ejemplo extremadamente simplificado, con advertencias a seguir:
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();
...
}
}
Esto tiene esencialmente el mismo efecto que usar una variable estática o singleton, pero se integra bastante bien en el marco de Android existente. Tenga en cuenta que esto no funcionará en todos los procesos (en caso de que su aplicación sea una de las raras que tiene múltiples procesos).
Algo a tener en cuenta en el ejemplo anterior; supongamos que hubiéramos hecho algo como:
class MyApp extends Application {
private String myState = /* complicated and slow initialization */;
public String getState(){
return myState;
}
}
Ahora esta lenta inicialización (como golpear el disco, golpear la red, bloquear cualquier cosa, etc.) se realizará cada vez que se instancia la aplicación. Puedes pensar, bueno, esto es solo una vez para el proceso y tendré que pagar el costo de todos modos, ¿verdad? Por ejemplo, como Dianne Hackborn menciona a continuación, es completamente posible que su proceso sea instanciado, solo para manejar un evento de transmisión en segundo plano. Si su procesamiento de transmisión no necesita este estado, puede haber realizado una serie de operaciones complicadas y lentas por nada. La instanciación perezosa es el nombre del juego aquí. La siguiente es una forma un poco más complicada de usar la aplicación que tiene más sentido para cualquier cosa que no sea el uso más simple:
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();
...
}
}
Si bien prefiero las subclases de aplicaciones a usar singletons aquí como la solución más elegante, prefiero que los desarrolladores usen singletons si es realmente necesario en lugar de no pensar en absoluto en el rendimiento y las implicaciones de subprocesos múltiples de asociar el estado con la subclase de aplicaciones.
NOTA 1: También como comentó anticafe, para vincular correctamente la anulación de su Aplicación a su aplicación, es necesaria una etiqueta en el archivo de manifiesto. Nuevamente, vea los documentos de Android para obtener más información. Un ejemplo:
<application
android:name="my.application.MyApp"
android:icon="..."
android:label="...">
</application>
NOTA 2: user608578 pregunta a continuación cómo funciona esto con la gestión de los ciclos de vida de objetos nativos. No estoy al tanto de usar código nativo con Android en lo más mínimo, y no estoy calificado para responder cómo interactuaría eso con mi solución. Si alguien tiene una respuesta a esto, estoy dispuesto a darles crédito y poner la información en esta publicación para una visibilidad máxima.
APÉNDICE:
Como algunas personas han notado, esta no es una solución para el estado persistente , algo que quizás debería haber enfatizado más en la respuesta original. Es decir, esto no está destinado a ser una solución para guardar información del usuario u otra información que debe persistir a lo largo de la vida útil de las aplicaciones. Por lo tanto, considero que la mayoría de las críticas a continuación se relacionan con aplicaciones que se eliminan en cualquier momento, etc., discutible, ya que todo lo que alguna vez necesitó persistir en el disco no debe almacenarse a través de una subclase de aplicación. Está destinado a ser una solución para almacenar el estado de aplicación temporal, fácilmente reproducible (si un usuario ha iniciado sesión, por ejemplo) y componentes que son de instancia única (administrador de red de aplicación, por ejemplo) (¡ NO singleton!) En la naturaleza.
Dayerman ha tenido la amabilidad de señalar una conversación interesante con Reto Meier y Dianne Hackborn en la que se desaconseja el uso de subclases de aplicaciones a favor de los patrones Singleton. Somatik también señaló algo de esta naturaleza antes, aunque no lo vi en ese momento. Debido al papel de Reto y Dianne en el mantenimiento de la plataforma Android, no puedo recomendar de buena fe ignorar sus consejos. Lo que dicen, va. Deseo no estar de acuerdo con las opiniones, expresadas con respecto a preferir Singleton sobre las subclases de aplicación. En mi desacuerdo, haré uso de los conceptos mejor explicados en esta explicación de StackExchange del patrón de diseño Singleton, para que no tenga que definir términos en esta respuesta. Recomiendo leer el enlace antes de continuar. Punto por punto:
Dianne dice: "No hay ninguna razón para subclase de la aplicación. No es diferente a hacer un singleton ..." Esta primera afirmación es incorrecta. Existen dos motivos principales para esto. 1) La clase de aplicación proporciona una mejor garantía de por vida para un desarrollador de aplicaciones; Se garantiza que tendrá la vida útil de la aplicación. Un singleton no está EXPLÍCITAMENTE vinculado a la vida útil de la aplicación (aunque sí lo es). Esto puede no ser un problema para un desarrollador de aplicaciones promedio, pero diría que este es exactamente el tipo de contrato que la API de Android debería ofrecer, y también proporciona mucha más flexibilidad al sistema Android, al minimizar la vida útil de los asociados. datos. 2) La clase de aplicación proporciona al desarrollador de la aplicación un único titular de instancia para el estado, que es muy diferente de un titular de estado Singleton. Para obtener una lista de las diferencias, consulte el enlace de explicación Singleton arriba.
Dianne continúa: "... es probable que sea algo de lo que se arrepienta en el futuro cuando encuentre que su objeto Aplicación se convierta en este gran enredo de lo que debería ser una lógica de aplicación independiente". Esto ciertamente no es incorrecto, pero esta no es una razón para elegir Singleton sobre la subclase de aplicación. Ninguno de los argumentos de Diane proporciona una razón por la cual usar un Singleton es mejor que una subclase de Aplicación, todo lo que intenta establecer es que usar un Singleton no es peor que una subclase de Aplicación, lo cual creo que es falso.
Ella continúa: "Y esto conduce de manera más natural a cómo se deben manejar estas cosas, inicializándolas a pedido". Esto ignora el hecho de que no hay ninguna razón por la que no pueda inicializar a pedido utilizando una subclase de aplicación también. De nuevo no hay diferencia.
Dianne termina con "El marco en sí tiene toneladas y toneladas de singletons para todos los pocos datos compartidos que mantiene para la aplicación, como cachés de recursos cargados, grupos de objetos, etc. Funciona muy bien". No estoy argumentando que usar Singletons no puede funcionar bien o no es una alternativa legítima. Estoy argumentando que Singletons no proporciona un contrato tan sólido con el sistema Android como el uso de una subclase de aplicaciones, y además que el uso de Singletons generalmente apunta a un diseño inflexible, que no se modifica fácilmente, y conduce a muchos problemas en el futuro. En mi humilde opinión, el fuerte contrato que la API de Android ofrece a las aplicaciones de desarrollador es uno de los aspectos más atractivos y agradables de la programación con Android, y ayudó a llevar a la adopción temprana del desarrollador que llevó a la plataforma Android al éxito que tiene hoy.
Dianne también ha comentado a continuación, mencionando una desventaja adicional del uso de subclases de aplicaciones, pueden alentar o facilitar la escritura de menos código de rendimiento. Esto es muy cierto, y he editado esta respuesta para enfatizar la importancia de considerar el rendimiento aquí y tomar el enfoque correcto si está utilizando la subclasificación de aplicaciones. Como dice Dianne, es importante recordar que su clase de Aplicación se instanciará cada vez que se cargue su proceso (¡podría ser varias veces a la vez si su aplicación se ejecuta en múltiples procesos!) Incluso si el proceso solo se carga para una transmisión en segundo plano evento. Por lo tanto, es importante utilizar la clase de aplicación más como un repositorio para punteros a componentes compartidos de su aplicación en lugar de como un lugar para realizar cualquier procesamiento.
Os dejo con la siguiente lista de desventajas de Singletons, tal como me lo robaron del enlace anterior de StackExchange:
- Incapacidad para usar clases abstractas o de interfaz;
- Incapacidad de subclase;
- Alto acoplamiento a través de la aplicación (difícil de modificar);
- Difícil de probar (no puede fingir / burlarse de las pruebas unitarias);
- Difícil de paralelizar en el caso de estado mutable (requiere un bloqueo extenso);
y agrego el mío:
- Contrato de por vida poco claro e inmanejable no apto para el desarrollo de Android (o la mayoría de los demás);