Pregunta

Estoy creando una aplicación que requiere inicio de sesión. He creado la actividad principal y el inicio de sesión.

En el método principal actividad onCreate I añadió 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 la forma de la conexión termina el aspecto siguiente:

@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 la forma de la conexión a veces aparece dos veces (el método login() se llama dos veces) y también cuando el teclado del teléfono se desliza el formulario de inscripción, aparece de nuevo y supongo que el problema es la strSessionString variable.

¿Alguien sabe cómo establecer la variable global con el fin de evitar el formulario de acceso que aparece después de que el usuario ya se autentica correctamente?

¿Fue útil?

Solución

escribí esta respuesta hacia atrás en el '09 cuando androide era relativamente nuevo, y había muchas áreas no están bien establecidos en el desarrollo de Android. He añadido un largo apéndice en la parte inferior de este post, abordar algunas críticas, y que detalla un desacuerdo filosófico que tengo con el uso de Singleton en lugar de subclases de aplicación. Leerlo en su propio riesgo.

RESPUESTA ORIGINAL:

El problema más general que está encontrando es cómo ahorrar estado a través de diversas actividades y todas las partes de su aplicación. Una variable estática (por ejemplo, un producto único) es una forma común de Java de lograr esto. He encontrado, sin embargo, que una forma más elegante en Android es asociar su estado con el contexto de aplicación.

Como saben, cada actividad es también un contexto, que es la 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 única instancia a través de su aplicación.

La forma de hacer esto es crear su propia subclase de android.app. aplicación y, a continuación, especifique esa clase en la etiqueta de aplicación en su manifiesto. Ahora Android creará automáticamente una instancia de esa clase y que esté disponible para toda la aplicación. Se puede acceder a él desde cualquier context utilizando el método Context.getApplicationContext() (Activity también proporciona un método getApplication() que tiene exactamente el mismo efecto). Lo que sigue es un ejemplo muy 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 utilizar una variable estática o Singleton, pero se integra muy bien en el marco de Android existentes. Tenga en cuenta que esto no funcionará a través de procesos (en caso de su aplicación para ser una de las pocas que tiene múltiples procesos).

Algo a tener en cuenta en el ejemplo anterior; supongamos vez que habíamos hecho algo como:

class MyApp extends Application {

  private String myState = /* complicated and slow initialization */;

  public String getState(){
    return myState;
  }
}

Ahora se realizará esta inicialización lenta (tales como golpear el disco, golpeando la red, algo bloqueando, etc.) cada vez que se crea una instancia de solicitud! Usted puede pensar, bueno, esto es sólo una vez para el proceso y voy a tener que pagar el costo de todos modos, ¿verdad? Por ejemplo, como Dianne Hackborn menciona más adelante, es perfectamente posible que el proceso para crear una instancia -just- para manejar un evento de trayectoria en transmisión. Si el procesamiento de emisión no tiene necesidad de este estado que haya potencialmente acaba de hacer toda una serie de operaciones complicadas y lentas para nada. instanciación perezoso es el nombre del juego aquí. La siguiente es una manera un poco más complicado de usar aplicación que hace más sentido para nada, pero el más simple de usos:

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();
    ...
  }
}

Mientras que prefiero subclases de aplicación a la utilización de conjuntos unitarios aquí como la solución más elegante, prefiero a los desarrolladores usar únicos cuando sea realmente necesario por no pensar en absoluto a través de las prestaciones y subprocesos múltiples implicaciones de la asociación de estado con la subclase de aplicación.

Nota 1: También como Anticafé comentado, con el fin de atar correctamente su solicitud de anulación de su aplicación una etiqueta es necesaria en el archivo de manifiesto. Una vez más, consulte la documentación 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 día en el uso de código nativo con Android en lo más mínimo, y no estoy capacitado para responder a la forma en que interactuarían con mi solución. Si alguien tiene una respuesta a esto, estoy dispuesto a darles crédito y poner la información en este post para una máxima visibilidad.

Adición:

Como algunas personas han señalado, esto es no una solución para persistente estado, algo que tal vez debería have hizo hincapié más en la respuesta original. Es decir. esto no está destinado a ser una solución para el ahorro de usuario u otra información que está destinado a ser persistido a través de tiempos de vida de la aplicación. Por lo tanto, considero que la crítica más abajo relacionadas con las aplicaciones que se mató en cualquier momento, etc ..., discutible, como todo lo que alguna vez tenía que ser mantenido en el disco no se debe almacenar a través de una subclase de aplicación. Está destinado a ser una solución para el almacenamiento, fácilmente re-creatable estado temporal de la aplicación (si un usuario se registra en por ejemplo) y los componentes que son solo caso (gestor de red de la aplicación, por ejemplo) ( NO singleton !) en la naturaleza.

Dayerman ha tenido la amabilidad de señalar un Reto Meier y Dianne Hackborn en el que el uso de las subclases de aplicación se aconseja en favor de los patrones Singleton. Somatik señaló también algo de esta naturaleza antes, aunque yo no lo vi en el momento. Debido a Reto y las funciones de Dianne en el mantenimiento de la plataforma Android, no puedo recomendar de buena fe haciendo caso omiso de sus consejos. Lo que dicen, va. Me hubiera gustado estar en desacuerdo con las opiniones, expresadas con respecto a preferir Singleton sobre las subclases de aplicación. En mi desacuerdo Voy a hacer uso de los conceptos explicados mejor en esta explicación StackExchange del patrón de diseño Singleton , de manera que yo no tengo que definir los términos en esta respuesta. Me animo a rozar el enlace antes de continuar. Punto por punto:

Dianne dice: "No hay ninguna razón para subclase de aplicación. No es diferente de hacer un producto único ..." Esta primera afirmación es incorrecta. Existen dos motivos principales para esto. 1) la clase de aplicación proporciona una garantía de por vida mejor para un desarrollador de aplicaciones; Está garantizado para tener el tiempo de vida de la aplicación. A singleton no es explícitamente ligada a la vida útil de la aplicación (aunque es efectiva). Esto puede ser un problema no para su desarrollador promedio de aplicación, pero yo diría que esto es exactamente el tipo de contrato de la API de Android tiene que haber prestado, y proporciona mucha más flexibilidad al sistema Android, así, reduciendo al mínimo el tiempo de vida de los asociados datos. 2) la clase de aplicación proporciona el desarrollador de la aplicación con un único soporte de ejemplo para el estado, que es muy diferente de un soporte de Singleton de estado. Para obtener una lista de las diferencias, consulte el enlace Singleton explicación anterior.

Dianne continúa, "... sólo probable que sea algo que se arrepentirá en el futuro como a encontrar su objeto de aplicación convirtiéndose esta gran maraña de lo que debería ser la lógica de aplicación independiente." Esto ciertamente no es incorrecto, pero esto no es una razón para elegir Singleton sobre Aplicación subclase. Ninguno de los argumentos de Diane proporcionar una razón que el uso de un Singleton es mejor que una subclase de aplicación, lo único que intenta establecer es que el uso de un Singleton no es peor que una subclase de aplicación, que creo que es falso.

Y continúa diciendo: "Y esto nos lleva de forma más natural a la forma en que debe ser la gestión de estas cosas - la inicialización de ellas bajo demanda." Esto ignora el hecho de que no hay ninguna razón por la que no se puede inicializar en la demanda utilizando una subclase de aplicaciones también. Una vez más, no hay diferencia.

Dianne termina con "El marco en sí tiene toneladas y toneladas de embarazos únicos para todos los pequeños de datos compartida que mantiene para la aplicación, tales como depósitos de recursos cargados, piscinas de objetos, etc. Funciona muy bien." No estoy diciendo que el uso de Singleton no puede funcionar bien o no son una alternativa legítima. Estoy argumentando que Singleton no proporcionan un contrato tan fuerte con el sistema Android como el uso de una subclase de aplicación, y, además, que utilizando Singleton apunta generalmente a desig inflexiblesn, que no se modifica fácilmente, y conduce a muchos problemas en el futuro. En mi humilde opinión, la fuerte contrato de la API de Android ofrece a los desarrolladores de aplicaciones es uno de los aspectos más atractivos y agradables de la programación con Android, y ayudó a conducir a la adopción de los primeros desarrolladores que llevó a la plataforma Android para el éxito que tiene hoy. Lo que sugiere el uso de Singleton se mueve de forma implícita lejos de un fuerte contrato de API, y en mi opinión, debilita el marco Android.

Dianne ha comentado a continuación, así, mencionar un inconveniente adicional para el uso de las subclases de aplicación, pueden estimular o hacer que sea más fácil escribir menos código rendimiento. Esto es muy cierto, y he editado esta respuesta para enfatizar la importancia de considerar Potencia aquí, y tomando el enfoque correcto si está usando subclases de aplicación. Como afirma Dianne, es importante recordar que su clase de aplicación se creará una instancia cada vez que se carga el proceso (podría ser varias veces a la vez, si la aplicación se ejecuta en múltiples procesos!) Incluso si el proceso sólo se carga para una emisión de fondo evento. Por tanto, es importante utilizar la clase de aplicación más como un repositorio para los punteros a los componentes compartidos de su aplicación, más que como un lugar para hacer cualquier procesamiento!

Los dejo con la siguiente lista de desventajas a Singleton, como robado desde el enlace anterior StackExchange:

  • Incapacidad para usar clases abstractas o interfaz;
  • Incapacidad de subclase;
  • High acoplamiento a través de la aplicación (difícil modificar);
  • difícil de probar (no puede falsificar / mock en pruebas de unidad);
  • Difícil para paralelizar en el caso de estado mutable (requiere extensa de bloqueo);

y añadir mi propia:

  • contrato de por vida poco claro y difícil de manejar inadecuado para Android (o la mayoría de) el desarrollo;

Otros consejos

Crear esta subclase

public class MyApp extends Application {
  String foo;
}

En el AndroidManifest.xml añadir android: name

Ejemplo

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

La forma sugerida por Soonil de mantener un estado de la aplicación es buena, sin embargo, tiene un punto débil - hay casos en que OS mata a todo el proceso de aplicación. Aquí está la documentación sobre este -. procesos y ciclos de vida

Considere un caso - su aplicación pasa a un segundo plano porque alguien le está llamando (aplicación de teléfono está en el primer plano ahora). En este caso && bajo algunas otras condiciones (ver el enlace anterior para lo que podría ser) el sistema operativo puede matar a su proceso de solicitud, incluyendo la instancia Application subclase. Como resultado de ello se pierde el estado. Cuando más tarde volver a la aplicación, a continuación, el sistema operativo restaurará su pila de la actividad y la instancia Application subclase, sin embargo será myState el campo null.

Que yo sepa, la única manera de garantizar la seguridad del estado es el uso de cualquier tipo de persistir el estado, por ejemplo, utilizando una privada para el archivo de aplicación o SharedPrefernces (el tiempo se utiliza una privada para el archivo de aplicación en el sistema de archivos interno).

Sólo una nota ..

añadir:

android:name=".Globals"

o lo que usted designó a su subclase a la existente etiqueta <application>. No dejaba de intentar añadir otra etiqueta <application> al manifiesto y conseguiría una excepción.

No pude encontrar la forma de especificar la etiqueta de aplicación o bien, pero después de mucho buscar en Google, se hizo evidente a partir de los documentos de archivo de manifiesto: el uso androide: nombre, además del icono predeterminado y la etiqueta en la estrofa aplicación.

android: nombre El nombre completo de la subclase de aplicación práctica 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 se necesita uno. En ausencia de una subclase, Android utiliza una instancia de la clase de aplicación base.

¿Qué hay de garantizar la recogida de la memoria nativa con tales estructuras globales?

Actividades tener un método onPause/onDestroy() que se llama a la destrucción, pero la clase de aplicación no tiene equivalentes. ¿Qué mecanismo se recomiendan para asegurar que las estructuras globales (especialmente aquellos que contienen referencias a la memoria nativa) se recogen basura adecuadamente cuando la aplicación está muerto o la pila tarea se pone en el fondo?

Sólo es necesario definir un nombre de aplicación, como a continuación que trabajará:

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

Al igual que no se discutió anteriormente OS podría matar a la aplicación sin ninguna notificación (no hay ningún evento OnDestroy) así que no hay manera de salvar estas variables globales.

SharedPreferences podría ser una solución a menos que usted tiene las variables de estructura compleja (en mi caso tuve matriz de enteros para almacenar los identificadores que el usuario ya ha manejado). El problema con los SharedPreferences es que es difícil de almacenar y recuperar estas estructuras cada vez que los valores necesarios.

En mi caso tuve un servicio en segundo plano para que pudiera moverse a estas variables allí y porque el servicio tiene caso OnDestroy, podría salvar a esos valores fácilmente.

Si algunas variables se almacenan en sqlite y hay que utilizarlos en la mayoría de las actividades en su aplicación. entonces la aplicación tal vez la mejor manera de lograrlo. Consultar las variables de la base de datos cuando se inicia una aplicación o almacenarlos en un campo. A continuación, puede utilizar estas variables en sus actividades.

Así que encontrar la manera correcta, y no hay mejor manera.

Puede tener un campo estático para almacenar este tipo de estado. Así como ponerlo en el paquete de recursos y restaurar a partir de ahí onCreate (Bundle savedInstanceState). Sólo asegúrese de entender completamente gestionada aplicación Android ciclo de vida (por ejemplo, ¿por login () obtiene la llamada sobre el cambio de orientación del teclado).

No Usar otra etiqueta <application> en el manifiesto file.Just lleve a cabo una modificación de la etiqueta <application> existente, añadir esta línea en la que android:name=".ApplicationName", ApplicationName será el nombre de la subclase (uso para almacenar global) eso, usted está a punto de crear.

Así que, finalmente su ÚNICO etiqueta <application> en el archivo de manifiesto debe 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"
        >

puede utilizar Propósitos, SQLite, o preferencias compartidas. Cuando se trata el medio de almacenamiento, como documentos, fotos, y videos, es posible crear los nuevos archivos en su lugar.

Puede hacer esto utilizando dos enfoques:

  1. Uso de clase Application
  2. Uso de Preferencias compartidas

  3. Uso de clase Application

Ejemplo:

class SessionManager extends Application{

  String sessionKey;

  setSessionKey(String key){
    this.sessionKey=key;
  }

  String getSessisonKey(){
    return this.sessionKey;
  }
}

Puede utilizar por encima de clase para implementar inicio de sesión en su MainActivity de la siguiente manera. 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. En realidad, no hace ninguna idea cuando el sistema operativo se va a matar a la aplicación, debido a baja memoria. Cuando la aplicación está en segundo plano y el usuario está navegando a través de otra aplicación que requiere más memoria para funcionar, entonces su solicitud será muerto desde el sistema operativo dado más prioridad a los procesos en primer plano que de fondo. Por lo tanto, su objeto de aplicación será nula antes que el usuario cierra la sesión. Por lo tanto para este recomiendo utilizar segundo método especificado anteriormente.

  1. El uso de 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");
    

En consecuencia la actividad se llama antes de reanudar. Así se mueve que se conecte a comprobar en el currículum y su segunda entrada puede ser bloqueada una vez que la actividad secomd ha devuelto un resultado positivo. En hoja de vida se llama cada vez que así que no hay preocupaciones de que no fuera llamado por primera vez.

El enfoque de subclases también ha sido utilizado por el marco Baracus. Desde mi punto de vista subclases Aplicación tenía la intención de trabajar con los ciclos de vida de Android; esto es lo que cualquier de contenedor de aplicación lo hace. En lugar de tener variables globales a continuación, me registro frijoles a este contexto un dejo beeing inyectan en cualquier clase manejable por el contexto. Cada instancia del bean inyectado en realidad es un singleton.

Consulte este ejemplo para obtener más información

¿Por qué hacer el trabajo manual si puede tener mucho más?

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();
    ...
    }
}

Se puede crear una clase que amplíe la clase Application y luego declarar la variable como un campo de esa clase y la disponibilidad método de obtención de la misma.

public class MyApplication extends Application {
    private String str = "My String";

    synchronized public String getMyString {
        return str;
    }
}

Y a continuación, acceder a esa variable en su actividad, utilice lo siguiente:

MyApplication application = (MyApplication) getApplication();
String myVar = application.getMyString();
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top