Usar la clase de aplicación de Android para conservar los datos

112

Estoy trabajando en una aplicación de Android bastante compleja que requiere una gran cantidad de datos sobre la aplicación (yo diría que un total de unos 500 KB, ¿es tan grande para un dispositivo móvil?). Por lo que puedo decir, cualquier cambio de orientación en la aplicación (en la actividad, para ser más precisos) provoca una completa destrucción y recreación de la actividad. Según mis hallazgos, la clase Application no tiene el mismo ciclo de vida (es decir, para todos los efectos, siempre se crea una instancia). ¿Tiene sentido almacenar la información de estado dentro de la clase de aplicación y luego hacer referencia a ella desde la Actividad, o ese generalmente no es el método "aceptable" debido a limitaciones de memoria en los dispositivos móviles? Realmente agradezco cualquier consejo sobre este tema. ¡Gracias!

Dave
fuente
8
Solo tenga en cuenta que los datos en su aplicación aún se pueden eliminar si su aplicación pasa a segundo plano, por lo que esta no es una solución para los datos persistentes que siempre desea poder recuperar. Simplemente sirve como un método para no tener que recrear objetos costosos con tanta frecuencia.
Cheryl Simon
2
Mayra; No creo que la aplicación se elimine "normalmente" (aunque, como alguien señala más adelante en este hilo, "puede" ser). Probablemente voy a optar por algún tipo de enfoque "híbrido" de usar la aplicación para almacenar y cargar los datos, pero luego usaré el atributo "android: orientación" en la actividad en el archivo de manifiesto para anular el comportamiento normal de derribando y reconstruyendo la actividad. Todo esto, por supuesto, supone que la aplicación puede determinar "cuándo" se está destruyendo para que los datos puedan conservarse.
Dave

Respuestas:

134

No creo que 500kb sea tan importante.

Lo que describió es exactamente cómo abordé mi problema de pérdida de datos en una actividad. Creé un singleton global en la clase Application y pude acceder a él desde las actividades que usé.

Puede pasar datos en un Singleton global si se va a utilizar mucho.

public class YourApplication extends Application 
{     
     public SomeDataClass data = new SomeDataClass();
}

Luego llámelo en cualquier actividad por:

YourApplication appState = ((YourApplication)this.getApplication());
appState.data.UseAGetterOrSetterHere(); // Do whatever you need to with the data here.

Lo analizo aquí en la publicación de mi blog , en la sección "Global Singleton".

Bryan Denny
fuente
1
Lamentablemente, la publicación del blog en cuestión ya no está disponible en esa dirección.
Mikebabcock
1
He estado moviendo cosas en mi sitio. Hasta que se solucione, puede encontrarlo en archive.org aquí: web.archive.org/web/20130818035631/http://www.bryandenny.com/…
Bryan Denny
1
Sé que esta es una publicación antigua, pero me encontré con un problema que podría resolver, sin embargo, esta clase debe declararse en el manifiesto de alguna manera, ¿no? No puedo acceder a la clase, así que siento que esto es lo que me estoy perdiendo ...
Ziv Kesten
1
@ZivKesten ¿Qué tal agregar el atributo name = a la etiqueta de la aplicación dentro del manifiesto?
MikeC
@mgc, gracias, ha pasado un tiempo, y sí, así es como finalmente lo resolví, también creé instancias de esa clase donde lo necesitaba dándole el getApplicationContext () con un elenco a esta clase
Ziv Kesten
57

Los que cuentan con la Applicationinstancia se equivocan. Al principio, puede parecer que Applicationexiste mientras exista todo el proceso de la aplicación, pero esta es una suposición incorrecta.

El sistema operativo puede matar procesos según sea necesario. Todos los procesos se dividen en 5 niveles de "matabilidad" especificados en el doc .

Entonces, por ejemplo, si su aplicación pasa a segundo plano debido a que el usuario responde a una llamada entrante, entonces, dependiendo del estado de la RAM, el sistema operativo puede (o no) matar su proceso (destruyendo la Applicationinstancia en el proceso) .

Creo que un mejor enfoque sería conservar sus datos en el archivo de almacenamiento interno y luego leerlos cuando se reanude su actividad.

ACTUALIZAR:

Recibí muchos comentarios negativos, por lo que es hora de agregar una aclaración. :) Bueno, inicialmente utilicé una suposición errónea de que el estado es realmente importante para la aplicación. Sin embargo, si su aplicación está bien y a veces se pierde el estado (podrían ser algunas imágenes que simplemente se volverán a leer / descargar), entonces está completamente bien mantenerla como miembro de Application.

Vit Khudenko
fuente
14
Si se mata la aplicación, ¿a quién le importa, verdad? La aplicación se ha ido. Según tengo entendido, Android recuperará procesos que contienen memoria como Actividades. Si se mata el proceso que contiene la aplicación (¿si Android incluso lo hará?), Eso es esencialmente como matar la aplicación. El usuario deberá volver a iniciar la aplicación y, en ese momento, ¿a quién le importa? Es una nueva instancia de la aplicación.
Andrew
14
Esta fue una sorpresa desagradable para nosotros en producción. Créame, Android mata los procesos, solo depende del estado de la RAM y otros factores descritos en la documentación. Fue una pesadilla para nosotros, así que solo comparto mi experiencia real. Bueno, no teníamos esto en los emuladores, pero en el mundo real algunos dispositivos están 'sobrecargados' con aplicaciones, por lo que eliminar un proceso en segundo plano es una situación normal. Sí, si el usuario decide poner la aplicación en primer plano, el sistema operativo restaura su pila, incluida la Applicationinstancia, sin embargo, no contará con sus datos estáticos a menos que los persista.
Vit Khudenko
2
Creo que probablemente usaré un enfoque híbrido. Ya conocía el truco del manifiesto para anular el cambio de orientación (que tiene otros beneficios). Dado que la aplicación es un juego, no estoy seguro de que conservar los datos entre lanzamientos sea lo suficientemente "importante"; aunque probablemente no sería muy difícil ya que la mayoría de los datos se pueden serializar (aunque no me gustaría serializar y anular la serialización entre cada cambio de orientación). Definitivamente aprecio el aporte. No diría que los que dependen de la instancia de la aplicación están "mal". Depende mucho de la aplicación :).
Dave
1
@Arhimed, estás generalizando demasiado tu respuesta. Y sugiriendo un enfoque estrecho basado en su suposición. Supuesto falso: los datos contenidos en las variables estáticas deben persistir en todas las sesiones de la aplicación. Puede haber numerosos casos de uso en los que los datos son triviales y no es necesario conservarlos de inmediato.
Mandar Limaye
2
Tengo alrededor de 1 MB de datos con una estructura complicada. Serializar / deserializar me puede costar hasta 2-3 segundos cuando el dispositivo está sobrecargado de trabajo. La idea de guardar / cargar entre actividades cuesta demasiado tiempo. Utilizo la aplicación como almacenamiento. Por supuesto, mi clase de datos almacenada en la instancia de la aplicación ha verificado todos los métodos: si los datos aún están vivos o deben cargarse. Así que Dave tiene que: 1. proporcionar funciones de carga / guardar 2. mantener los datos en la aplicación. 3. Lógica de triple verificación para acceder a los datos.
Kostadin
6

Si desea acceder al "Singleton global" fuera de una actividad y no desea pasar a Contexttravés de todos los objetos involucrados para obtener el singleton, puede simplemente definir un atributo estático en su clase de aplicación, que contiene la referencia a sí mismo. Simplemente inicialice el atributo en el onCreate()método.

Por ejemplo:

public class ApplicationController extends Application {
    private static ApplicationController _appCtrl;

    public static ApplicationController getAppCtrl()
    {
         return _appCtrl;
    }
}

Debido a que las subclases de Applicationtambién pueden obtener los Recursos, puede acceder a ellos simplemente cuando define un método estático, que los devuelve, como:

public static Resources getAppResources()
{
    return _appCtrl.getResources();
}

Pero tenga mucho cuidado al pasar las referencias de contexto para evitar pérdidas de memoria .

saxos
fuente
6
Olvidó notar que debe agregar el atributo xml android: name = ". ApplicationController" la etiqueta de la aplicación en su manifiesto para que la clase sea instanciada.
eggie5
En realidad, no es necesario extender Applicationpara hacer esto. Puede declarar una variable miembro estática en cualquier clase para hacer esto.
David Wasser
2

Dave, ¿qué tipo de datos son? Si se trata de datos generales que pertenecen a la aplicación en su conjunto (ejemplo: datos de usuario), amplíe la clase Aplicación y guárdelos allí. Si los datos pertenecen a la actividad, debe usar los controladores onSaveInstanceState y onRestoreInstanceState para conservar los datos en la rotación de la pantalla.

Andrés
fuente
¿Qué pasa si los datos son realmente grandes para almacenar en un paquete? Esto es lo que obtengo: android.os.TransactionTooLargeException: tamaño del paquete de datos 838396 bytes
Arjun Issar
1

De hecho, puede anular la funcionalidad de orientación para asegurarse de que su actividad no se destruya ni se vuelva a crear. Mira aquí .

Grantland Chew
fuente
16
Puedes hacer muchas cosas. No significa que sean buenas ideas. No es buena idea.
Andrew
Probar cambiando la orientación de la pantalla es la forma más fácil de asegurarse de que su aplicación haga lo que Android supone que debe hacer.
18446744073709551615
0

Puede crear una clase de aplicación y guardar todos sus datos en esa llamada para usarla en cualquier lugar de su aplicación.

Ashish Jaiswal
fuente
0

Sé que esta es la pregunta muy antigua, pero usar ViewModel de los componentes del jetpack es la mejor manera de preservar los datos entre la rotación de actividades.

La clase ViewModel está diseñada para almacenar y administrar datos relacionados con la interfaz de usuario de una manera consciente del ciclo de vida. La clase ViewModel permite que los datos sobrevivan a los cambios de configuración, como las rotaciones de pantalla.

Dharmendra
fuente