Estoy creando una aplicación que requiere inicio de sesión. Creé la actividad principal y de inicio de sesión.
En el onCreate
método de actividad principal agregué la siguiente condición:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
...
loadSettings();
if(strSessionString == null)
{
login();
}
...
}
El onActivityResult
método que se ejecuta cuando finaliza el formulario de inicio de sesión tiene este aspecto:
@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);
}
}
}
El problema es que el formulario de inicio de sesión a veces aparece dos veces (el login()
método se llama dos veces) y también cuando se desliza el teclado del teléfono, el formulario de inicio de sesión aparece nuevamente y supongo que el problema es la variable strSessionString
.
¿Alguien sabe cómo configurar la variable global para evitar que aparezca el formulario de inicio de sesión después de que el usuario ya se haya autenticado correctamente?
android
singleton
global-variables
state
Niko Gamulin
fuente
fuente
Respuestas:
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 elContext.getApplicationContext()
método (Activity
también proporciona un métodogetApplication()
que tiene exactamente el mismo efecto). El siguiente es un ejemplo extremadamente simplificado, con advertencias a seguir: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:
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:
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:
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:
y agrego el mío:
fuente
Crea esta subclase
En AndroidManifest.xml agregue android: nombre
Ejemplo
fuente
java.lang.IllegalAccessException: access to class is not allowed
La forma sugerida por Soonil de mantener un estado para la aplicación es buena, sin embargo, tiene un punto débil: hay casos en que el sistema operativo mata todo el proceso de la aplicación. Aquí está la documentación sobre esto: procesos y ciclos de vida .
Considere un caso: su aplicación pasa a un segundo plano porque alguien lo está llamando (la aplicación del teléfono está en primer plano ahora). En este caso, && bajo otras condiciones (consulte el enlace anterior para ver cuáles podrían ser) el sistema operativo puede matar su proceso de solicitud, incluida la
Application
instancia de la subclase. Como resultado, el estado se pierde. Cuando más tarde regrese a la aplicación, el sistema operativo restaurará suApplication
instancia de pila de actividad y subclase, sin embargo, elmyState
campo seránull
.AFAIK, la única forma de garantizar la seguridad del estado es usar cualquier tipo de persistencia del estado, por ejemplo, usar un archivo privado para el archivo de la aplicación o
SharedPrefernces
(eventualmente usa un archivo privado para el archivo de la aplicación en el sistema de archivos interno).fuente
SharedPreferences
; así es como lo he visto hacer. Me resulta extraño abusar del sistema de preferencias para el estado guardado, pero funciona tan bien que el problema se convierte en una cuestión de terminología.Solo una nota ..
añadir:
o lo que sea que haya llamado su subclase a la etiqueta existente
<application>
. Seguí intentando agregar otra<application>
etiqueta al manifiesto y obtendría una excepción.fuente
Tampoco pude encontrar cómo especificar la etiqueta de la aplicación, pero después de mucho Googlear, se hizo evidente a partir de los documentos del archivo de manifiesto: use android: name, además del icono y la etiqueta predeterminados en la sección de la aplicación.
android: nombre El nombre completo de una subclase de aplicación implementada para la aplicación. Cuando se inicia el proceso de solicitud, esta clase se instancia antes que cualquiera de los componentes de la aplicación.
La subclase es opcional; La mayoría de las aplicaciones no necesitarán una. En ausencia de una subclase, Android utiliza una instancia de la clase de aplicación base.
fuente
¿Qué hay de garantizar la recopilación de memoria nativa con tales estructuras globales?
Las actividades tienen un
onPause/onDestroy()
método que se llama destrucción, pero la clase Aplicación no tiene equivalentes. ¿Qué mecanismo se recomienda para garantizar que las estructuras globales (especialmente aquellas que contienen referencias a la memoria nativa) se recolecten de manera apropiada cuando la aplicación se cierra o la pila de tareas se pone en segundo plano?fuente
Solo necesita definir un nombre de aplicación como el siguiente que funcionará:
fuente
Como se discutió anteriormente, el sistema operativo podría matar la APLICACIÓN sin ninguna notificación (no hay evento onDestroy), por lo que no hay forma de guardar estas variables globales.
SharedPreferences podría ser una solución, EXCEPTO que tenga variables ESTRUCTURADAS COMPLEJAS (en mi caso, tuve una matriz entera para almacenar las ID que el usuario ya ha manejado). El problema con SharedPreferences es que es difícil almacenar y recuperar estas estructuras cada vez que se necesitan los valores.
En mi caso, tenía un SERVICIO en segundo plano para poder mover estas variables allí y debido a que el servicio tiene un evento onDestroy, podría guardar esos valores fácilmente.
fuente
Si algunas variables se almacenan en sqlite y debe usarlas en la mayoría de las actividades de su aplicación. entonces la aplicación quizás sea la mejor manera de lograrlo. Consulte las variables de la base de datos cuando se inició la aplicación y almacénelas en un campo. Entonces puede usar estas variables en sus actividades.
Así que encuentra el camino correcto, y no hay mejor manera.
fuente
Puede tener un campo estático para almacenar este tipo de estado. O póngalo en el paquete de recursos y restaure desde allí en onCreate (Bundle savedInstanceState). Solo asegúrese de comprender completamente el ciclo de vida administrado de la aplicación de Android (por ejemplo, por qué se invoca a login () en el cambio de orientación del teclado).
fuente
NO USE otra
<application>
etiqueta en el archivo de manifiesto. Solo haga un cambio en la<application>
etiqueta existente , agregue esta líneaandroid:name=".ApplicationName"
donde,ApplicationName
estará el nombre de su subclase (use para almacenar global) que está a punto de crear.entonces, finalmente, su etiqueta ÚNICA
<application>
en el archivo de manifiesto debería verse así:fuente
puede usar Intents, Sqlite o Preferencias compartidas. Cuando se trata del almacenamiento de medios, como documentos, fotos y videos, puede crear los nuevos archivos.
fuente
Puede hacer esto usando dos enfoques:
Usar preferencias compartidas
Usando la clase de aplicación
Ejemplo:
Puede usar la clase anterior para implementar el inicio de sesión en su MainActivity como se muestra a continuación. El código se verá así:
Este método funcionará para el almacenamiento temporal. Realmente no tienes idea de cuándo el sistema operativo va a matar la aplicación, debido a la poca memoria. Cuando su aplicación está en segundo plano y el usuario está navegando a través de otra aplicación que requiere más memoria para ejecutarse, entonces su aplicación será eliminada ya que el sistema operativo da más prioridad a los procesos en primer plano que en segundo plano. Por lo tanto, su objeto de aplicación será nulo antes de que el usuario cierre sesión. Por lo tanto, para esto recomiendo usar el segundo método especificado anteriormente.
Usando preferencias compartidas.
fuente
El resultado de la actividad se llama antes en el currículum. Por lo tanto, mueva su verificación de inicio de sesión al reanudar y su segundo inicio de sesión se puede bloquear una vez que la actividad secundaria haya devuelto un resultado positivo. Al reanudar se llama cada vez, por lo que no hay que preocuparse de que no se llame la primera vez.
fuente
El enfoque de subclases también ha sido utilizado por el marco BARACUS. Desde mi punto de vista, la aplicación de subclases tenía la intención de funcionar con los ciclos de vida de Android; esto es lo que hace cualquier contenedor de aplicaciones. Entonces, en lugar de tener globales, registro frijoles en este contexto y los dejo inyectar en cualquier clase manejable por el contexto. Cada instancia de bean inyectado en realidad es un singleton.
Vea este ejemplo para más detalles.
¿Por qué hacer trabajo manual si puedes tener mucho más?
fuente
fuente
Puede crear una clase que extienda la
Application
clase y luego declarar su variable como un campo de esa clase y proporcionarle un método getter.Y luego para acceder a esa variable en su Actividad, use esto:
fuente