variable usar studio publicas globales for declarar crear all activities android singleton global-variables state

studio - usar variables globales en android



¿Cómo declarar variables globales en Android? (17)

¿Qué hay de asegurar la colección de memoria nativa con tales estructuras globales?

Las actividades tienen un onPause/onDestroy() que se llama a la destrucción, pero la clase Application no tiene equivalentes. ¿Qué mecanismo se recomienda para garantizar que las estructuras globales (especialmente las que contienen referencias a la memoria nativa) se recolecten de manera adecuada cuando la aplicación se elimina o la pila de tareas se coloca en segundo plano?

Estoy creando una aplicación que requiere inicio de sesión. Creé la actividad principal y de inicio de sesión.

En la actividad principal del método onCreate agregué la siguiente condición:

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ... loadSettings(); if(strSessionString == null) { login(); } ... }

El método onActivityResult que se ejecuta cuando finaliza el formulario de inicio de sesión se ve así:

@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 método de login() se llama dos veces) y también cuando el teclado del teléfono se desliza, 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 el formulario de inicio de sesión aparezca después de que el usuario se haya autenticado con éxito?


Como se discutió anteriormente, el SO podría matar la APLICACIÓN sin ninguna notificación (no hay un evento onDestroy), por lo que no hay forma de guardar estas variables globales.

SharedPreferences podría ser una solución EXCEPTO que tenga variables COMPLEJAS ESTRUCTURADAS (en mi caso tuve una matriz de enteros para almacenar las ID que el usuario ya ha manejado). El problema con las SharedPreferences es que es difícil almacenar y recuperar estas estructuras cada vez que se necesitan los valores.

En mi caso, tuve un SERVICIO de fondo, por lo que pude mover estas variables allí y debido a que el servicio tiene un evento de Destrucción, podría guardar esos valores fácilmente.


Crear esta subclase

public class MyApp extends Application { String foo; }

En el AndroidManifest.xml agrega android: name

Ejemplo

<application android:name=".MyApp" android:icon="@drawable/icon" android:label="@string/app_name">


El enfoque de subclasificación también ha sido utilizado por el marco de BARACUS. Desde mi punto de vista, la aplicación de subclases estaba destinada a trabajar con los ciclos de vida de Android; esto es lo que hace cualquier Application Container. En lugar de tener globales entonces, registro frijoles en este contexto y los dejo inyectados en cualquier clase manejable por el contexto. Cada instancia de frijol inyectado en realidad es un singleton.

Vea este ejemplo para más detalles.

¿Por qué trabajar manualmente si puedes tener mucho más?


El resultado de la actividad se llama antes de reanudar. Por lo tanto, mueva la verificación de inicio de sesión al reanudar y su segundo inicio de sesión se puede bloquear una vez que la actividad de secomd haya dado un resultado positivo. El currículum se llama cada vez, por lo que no hay preocupaciones de que no se llame la primera vez.


Escribí esta respuesta en el ''09 cuando Android era relativamente nuevo, y había muchas áreas no bien establecidas en el desarrollo de Android. He agregado un extenso apéndice en la parte inferior 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 la subclasificación de la Aplicación. Léelo bajo su propio riesgo.

RESPUESTA ORIGINAL:

El problema más general que está encontrando es cómo guardar el estado en varias Actividades y en 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 también es 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 sola instancia en su aplicación.

La forma de hacerlo es crear su propia subclase de aplicación 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 la aplicación. Puede acceder a él desde cualquier context utilizando el método Context.getApplicationContext() (la Activity también proporciona un método getApplication() que tiene el mismo efecto). A continuación se muestra un ejemplo extremadamente simplificado, con las siguientes advertencias:

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 (si su aplicación es 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 inicialización lenta (como golpear el disco, golpear la red, bloquear cualquier cosa, etc.) se realizará cada vez que la aplicación se ejecute. Puede pensar, bueno, esto es solo una vez para el proceso y tendré que pagar el costo de todos modos, ¿verdad? Por ejemplo, como menciona Dianne Hackborn a continuación, es totalmente posible que su proceso se ejecute de manera justa para manejar un evento de transmisión en segundo plano. Si su procesamiento de transmisión no necesita este estado, es posible que haya hecho toda una serie de operaciones lentas y complicadas para nada. La instanciación perezosa es el nombre del juego aquí. La siguiente es una forma un poco más complicada de usar una aplicación que tiene más sentido para cualquier cosa que no sea la más sencilla de usar:

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 la subclase de aplicaciones a usar singletons aquí como la solución más elegante, preferiría que los desarrolladores usen singletons si es realmente necesario en lugar de no pensar en absoluto a través del rendimiento y las implicaciones de subprocesos múltiples de asociar el estado con la subclase de la aplicación.

NOTA 1: También como comentó anticafe, para vincular correctamente la anulación de su aplicación a su aplicación, se necesita una etiqueta en el archivo de manifiesto. Una vez más, ver la documentación de Android para 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 administración de ciclos de vida de objetos nativos. No estoy en condiciones de usar código nativo con Android en lo más mínimo, y no estoy calificado para responder cómo interactuaría con mi solución. Si alguien tiene una respuesta a esto, estoy dispuesto a acreditarlo y poner la información en este post para la máxima visibilidad.

APÉNDICE:

Como algunas personas han señalado, 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 pretende ser una solución para guardar al usuario u otra información que deba persistir a lo largo de la vida útil de la aplicación. Por lo tanto, considero que la mayoría de las críticas a continuación se relacionan con la eliminación de las aplicaciones en cualquier momento, etc., discutibles, ya que cualquier cosa que haya que persistir en el disco no debe almacenarse a través de una subclase de la aplicación. Está pensado para ser una solución para almacenar el estado de la aplicación temporal y fácilmente reproducible (si un usuario está registrado, por ejemplo) y componentes que son una instancia única (administrador de red de la 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 en favor de los patrones de Singleton. Somatik también señaló algo de esta naturaleza antes, aunque no lo vi en ese momento. Debido a los roles 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 la preferencia de 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 de Singleton , para que no tenga que definir términos en esta respuesta. Les recomiendo que hojeen el enlace antes de continuar. Punto por punto:

Dianne dice: "No hay razón para subclasificar desde 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 Aplicación proporciona una mejor garantía de por vida para un desarrollador de aplicaciones; Se garantiza tener la vida útil de la aplicación. Un singleton no está EXPLICITAMENTE vinculado a la vida útil de la aplicación (aunque sí lo es). Esto puede no ser un problema para su desarrollador de aplicaciones promedio, pero diría que este es exactamente el tipo de contrato que debería ofrecer la API de Android, y también proporciona mucha más flexibilidad para el sistema Android, al minimizar la vida útil de los asociados. datos. 2) La clase 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 Singleton del estado. Para obtener una lista de las diferencias, consulte el enlace de explicación de Singleton anterior.

Dianne continúa: "... es probable que sea algo de lo que te arrepientas en el futuro cuando encuentres que tu objeto de Aplicación se está convirtiendo en este gran enredo de lo que debería ser una lógica de aplicación independiente". Esto ciertamente no es incorrecto, pero no es una razón para elegir Singleton sobre la subclase de la aplicación. Ninguno de los argumentos de Diane proporciona una razón por la que usar un Singleton es mejor que una subclase de la aplicación, todo lo que intenta establecer es que usar un Singleton no es peor que una subclase de la aplicación, lo que creo que es falso.

Ella continúa: "Y esto conduce de manera más natural a cómo debes manejar estas cosas, inicializándolas a pedido". Esto ignora el hecho de que no hay ninguna razón por la que no se pueda inicializar bajo demanda usando una subclase de aplicación también. De nuevo no hay diferencia.

Dianne termina con "El marco en sí mismo tiene toneladas y toneladas de singletons para todos los pocos datos compartidos que mantiene para la aplicación, como cachés de recursos cargados, conjuntos de objetos, etc. Funciona muy bien". No estoy argumentando que el uso de Singletons no funcione bien o no sea una alternativa legítima. Estoy argumentando que Singletons no ofrece un contrato tan fuerte con el sistema Android como el uso de una subclase de aplicación, y además, 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 desarrolladores 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 de desarrolladores, lo que llevó a la plataforma Android al éxito que tiene hoy. La sugerencia de usar Singletons se está alejando implícitamente de un contrato de API fuerte, y en mi opinión, debilita el marco de Android.

Dianne también ha comentado a continuación, mencionando un inconveniente adicional al uso de subclases de aplicaciones, pueden alentar o hacer que sea más fácil escribir menos código de rendimiento. Esto es muy cierto, y he editado esta respuesta para enfatizar la importancia de considerar la perfección aquí y el enfoque correcto si está usando subclases de aplicaciones. Como afirma Dianne, es importante recordar que su clase de aplicación se creará una instancia 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 está cargando para una transmisión en segundo plano evento. Por lo tanto, es importante utilizar la clase de aplicaciones más como un repositorio para los punteros a los componentes compartidos de su aplicación en lugar de un lugar para realizar cualquier procesamiento.

Os dejo con la siguiente lista de desventajas de Singletons, como robada del enlace anterior de StackExchange:

  • Incapacidad para utilizar 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 se puede simular / simular en pruebas de unidad);
  • Es difícil paralelizar en el caso de un estado mutable (requiere un bloqueo extenso);

y añadir mi propia

  • Contrato de por vida poco claro e inmanejable inadecuado para el desarrollo de Android (o la mayoría de los otros);

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 destruye 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 al fondo porque alguien lo está llamando (la aplicación Teléfono está en primer plano ahora). En este caso, && bajo algunas otras condiciones (verifique el enlace anterior para ver cuáles podrían ser) el sistema operativo puede detener el proceso de su aplicación, incluida la instancia de subclase de la Application . Como resultado el estado se pierde. Cuando luego vuelva a la aplicación, el sistema operativo restaurará su pila de actividad y la instancia de subclase de la Application , sin embargo, el campo myState será null .

AFAIK, la única forma de garantizar la seguridad del estado es usar cualquier tipo de persistencia del estado, por ejemplo, usar un privado para el archivo de la aplicación o SharedPrefernces (eventualmente usa un privado para el archivo de la aplicación en el sistema de archivos interno).


Podría crear una clase que amplíe la clase de Application y luego declarar su variable como un campo de esa clase y proporcionarle un método de obtención.

public class MyApplication extends Application { private String str = "My String"; synchronized public String getMyString { return str; } }

Y luego para acceder a esa variable en su Actividad, use esto:

MyApplication application = (MyApplication) getApplication(); String myVar = application.getMyString();


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 llama a login () en el cambio de orientación del teclado).


Puedes hacer esto usando dos enfoques:

  1. Usando la clase de aplicación
  2. Usando Preferencias Compartidas

  3. Usando la clase de aplicación

Ejemplo:

class SessionManager extends Application{ String sessionKey; setSessionKey(String key){ this.sessionKey=key; } String getSessisonKey(){ return this.sessionKey; } }

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á algo como esto:

@override public void onCreate (Bundle savedInstanceState){ // you will this key when first time login is successful. SessionManager session= (SessionManager)getApplicationContext(); String key=getSessisonKey.getKey(); //Use this key to identify whether session is alive or not. }

Este método funcionará para el almacenamiento temporal. Realmente no tienes idea cuando 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 se eliminará ya que el sistema operativo tiene más prioridad en los procesos de primer plano que en segundo plano. Por lo tanto, su objeto de aplicación será nulo antes de que el usuario cierre la sesión. Por lo tanto para esto recomiendo usar el segundo método especificado anteriormente.

  1. Usando preferencias compartidas.

    String MYPREF="com.your.application.session" SharedPreferences pref= context.getSharedPreferences(MyPREF,MODE_PRIVATE); //Insert key as below: Editot editor= pref.edit(); editor.putString("key","value"); editor.commit(); //Get key as below. SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE); String key= getResources().getString("key");


Puedes usar Intents, Sqlite o Shared Preferences. Cuando se trata del almacenamiento de medios, como documentos, fotos y videos, puede crear los nuevos archivos en su lugar.


Si algunas variables se almacenan en sqlite y debe usarlas en la mayoría de las actividades en su aplicación. Entonces la aplicación tal vez 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. Luego puedes usar estas variables en tus actividades.

Así que encuentra el camino correcto, y no hay mejor manera.


Solo necesita definir un nombre de aplicación como el siguiente que funcionará:

<application android:name="ApplicationName" android:icon="@drawable/icon"> </application>


Solo una nota ..

añadir:

android:name=".Globals"

o lo que sea que nombró su subclase a la etiqueta existente <application> . Seguí intentando agregar otra etiqueta de <application> al manifiesto y obtendría una excepción.


Tampoco pude encontrar la forma de especificar la etiqueta de la aplicación, pero después de una gran cantidad de Google, 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 aplicaciones.

android: name El nombre completo de una subclase de aplicación implementada para la aplicación. Cuando se inicia el proceso de solicitud, esta clase se crea una 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 usa una instancia de la clase de aplicación base.


NO use otra etiqueta <application> en el archivo de manifiesto. Solo haga un cambio en la etiqueta <application> existente, agregue esta línea android:name=".ApplicationName" donde, ApplicationName será el nombre de su subclase (use para almacenar global ) eso, tu estas a punto de crear.

así que, finalmente, su etiqueta ONE AND ONLY <application> en el archivo de manifiesto debería tener este aspecto: -

<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/Theme.AppCompat.NoActionBar" android:name=".ApplicationName" >


class GlobaleVariableDemo extends Application { private String myGlobalState; public String getGlobalState(){ return myGlobalState; } public void setGlobalState(String s){ myGlobalState = s; } } class Demo extends Activity { @Override public void onCreate(Bundle b){ ... GlobaleVariableDemo appState = ((GlobaleVariableDemo)getApplicationContext()); String state = appState.getGlobalState(); ... } }