¿Cómo declarar variables globales en Android?

Resuelto Niko Gamulin asked hace 54 años • 17 respuestas

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

En el onCreatemé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 onActivityResultmé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 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 aparezca el formulario de inicio de sesión después de que el usuario ya se haya autenticado correctamente?

Niko Gamulin avatar Jan 01 '70 08:01 Niko Gamulin
Aceptado

Escribí esta respuesta en 2009, cuando Android era relativamente nuevo y había muchas áreas no bien establecidas en el desarrollo de Android. Agregué un apéndice extenso al final de esta publicación, abordando algunas críticas y detallando un desacuerdo filosófico que tengo con el uso de Singletons en lugar de subclasificar la Aplicación. Léelo bajo tu propia responsabilidad.

RESPUESTA ORIGINAL:

El problema más general que encuentra 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 en Java de lograr esto. Sin embargo, descubrí que una forma más elegante en Android es asociar su estado con el contexto de la aplicación.

Como sabes, 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 instancia única en toda 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 método contextutilizando el Context.getApplicationContext()método ( Activitytambién proporciona un método getApplication()que tiene exactamente el mismo efecto). A continuación se muestra un ejemplo extremadamente simplificado, con algunas 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 trabajo 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 del ejemplo anterior; supongamos que en lugar de eso 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 acceder al disco, acceder a la red, bloquear cualquier cosa, etc.) se realizará cada vez que se cree una instancia de la aplicación. Quizás pienses, bueno, esto es sólo una vez para el proceso y tendré que pagar el costo de todos modos, ¿no? Por ejemplo, como Dianne Hackborn menciona a continuación, es completamente posible crear una instancia de su proceso (solo) para manejar un evento de transmisión en segundo plano. Si su procesamiento de transmisión no necesita este estado, potencialmente habrá realizado toda una serie de operaciones lentas y complicadas en vano. La creación de instancias diferida 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 uso excepto para los usos más simples:

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 Aplicación al uso de singletons aquí como la solución más elegante, prefiero que los desarrolladores usen singletons si realmente es 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 Aplicación.

NOTA 1: Además, 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, consulte 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: el usuario608578 pregunta a continuación cómo funciona esto con la gestión de los ciclos de vida de los objetos nativos. No estoy al día en el uso de 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 darle crédito y poner la información en esta publicación para una máxima visibilidad.

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 pretende ser una solución para guardar información del usuario u otra información que deba persistir durante la vida útil de la aplicación. Por lo tanto, considero que la mayoría de las críticas a continuación relacionadas con la eliminación de aplicaciones en cualquier momento, etc., son discutibles, ya que cualquier cosa que alguna vez deba 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 la aplicación temporal y fácilmente recreable (ya sea que un usuario haya iniciado sesión, por ejemplo) y componentes que son de instancia única (administrador de red de aplicaciones, por ejemplo) (¡NO singleton !) por 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 patrones Singleton. Somatik también señaló algo de esta naturaleza anteriormente, aunque yo no lo vi en ese momento. Debido a las funciones de Reto y Dianne en el mantenimiento de la plataforma Android, no puedo recomendar de buena fe ignorar sus consejos. Lo que dicen, se va. Deseo no estar de acuerdo con las opiniones expresadas con respecto a preferir las subclases Singleton a las de Aplicación. En mi desacuerdo, utilizaré conceptos que se explican mejor en esta explicación de StackExchange del patrón de diseño Singleton , para no tener que definir términos en esta respuesta. Recomiendo encarecidamente hojear el enlace antes de continuar. Punto por punto:

Dianne afirma: "No hay motivo para subclasificar la Aplicación. No es diferente a crear 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 que tendrá la vida útil de la aplicación. Un singleton no está explícitamente ligado a la vida útil de la aplicación (aunque sí lo está). Esto puede no ser un problema para el desarrollador de aplicaciones promedio, pero yo 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 las aplicaciones asociadas. datos. 2) La clase Aplicación proporciona al desarrollador de la aplicación un titular de instancia única 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 de Singleton anterior.

Dianne continúa: "...es probable que sea algo de lo que se arrepienta en el futuro cuando descubra que su objeto Aplicación se convierte en un gran lío de lo que debería ser una lógica de aplicación independiente". Ciertamente, esto no es incorrecto, pero no es una razón para elegir la subclase Singleton en lugar 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 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.

Y continúa: "Y esto conduce de forma más natural a cómo se deben gestionar estas cosas: inicializarlas según demanda". Esto ignora el hecho de que no hay ninguna razón por la que no pueda inicializarse bajo demanda utilizando también una subclase de Aplicación. Nuevamente no hay diferencia.

Dianne termina diciendo: "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 diciendo que el uso de Singletons no pueda funcionar bien o que no sea una alternativa legítima. Sostengo que los Singletons no proporcionan un contrato tan sólido 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 sólido contrato que la API de Android ofrece a los desarrolladores de aplicaciones es uno de los aspectos más atractivos y placenteros de la programación con Android, y ayudó a llevar a la adopción temprana por parte de los desarrolladores, lo que impulsó la plataforma Android al éxito que tiene hoy. Sugerir el uso de Singletons es alejarse implícitamente de un contrato API sólido y, en mi opinión, debilita el marco de Android.

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 código con menos rendimiento. Esto es muy cierto y he editado esta respuesta para enfatizar la importancia de considerar el rendimiento aquí y adoptar el enfoque correcto si está utilizando subclases de aplicaciones. Como dice Dianne, es importante recordar que se creará una instancia de su clase Aplicación 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 Aplicación más como un repositorio de punteros a componentes compartidos de su aplicación que como un lugar para realizar cualquier procesamiento.

Los dejo con la siguiente lista de desventajas de los Singleton, robadas del enlace anterior de StackExchange:

  • Incapacidad para utilizar clases abstractas o de interfaz;
  • Incapacidad para subclasificar;
  • Alto acoplamiento en toda la aplicación (difícil de modificar);
  • Difícil de probar (no se puede falsificar ni burlarse en pruebas unitarias);
  • Difícil de paralelizar en el caso de un estado mutable (requiere un bloqueo extenso);

y agrego el mio propio:

  • Contrato de por vida poco claro e inmanejable, inadecuado para el desarrollo de Android (o la mayoría de los demás);
sooniln avatar Apr 02 '2009 04:04 sooniln

Crea esta subclase

public class MyApp extends Application {
  String foo;
}

En AndroidManifest.xml agregue android:nombre

Ejemplo

<application android:name=".MyApp" 
       android:icon="@drawable/icon" 
       android:label="@string/app_name">
Guillaume avatar Jul 26 '2010 20:07 Guillaume