Utilizzo della classe dell'applicazione Android per rendere persistenti i dati


112

Sto lavorando su un'applicazione Android abbastanza complessa che richiede una quantità piuttosto grande di dati sull'applicazione (direi un totale di circa 500 KB - è grande per un dispositivo mobile?). Da quello che posso dire, qualsiasi cambiamento di orientamento nell'applicazione (nell'attività, per essere più precisi) provoca una completa distruzione e ricreazione dell'attività. In base alle mie scoperte, la classe Application non ha lo stesso ciclo di vita (cioè è, a tutti gli effetti, sempre istanziata). Ha senso memorizzare le informazioni sullo stato all'interno della classe dell'applicazione e quindi farvi riferimento dall'attività, o questo generalmente non è il metodo "accettabile" a causa dei vincoli di memoria sui dispositivi mobili? Apprezzo davvero qualsiasi consiglio su questo argomento. Grazie!


8
Tieni presente che i dati nella tua applicazione possono ancora essere eliminati se la tua app passa in background, quindi questa non è una soluzione per i dati persistenti che desideri sempre poter recuperare. Serve solo come metodo per non dover ricreare oggetti costosi così spesso.
Cheryl Simon

2
Mayra; Non credo che l'app sia "normalmente" cancellata (anche se, come qualcuno sottolinea più avanti in questo thread, "può" esserlo). Probabilmente userò un approccio "ibrido" per utilizzare l'applicazione per memorizzare e caricare i dati, ma poi utilizzare l'attributo "android: orientamento" sull'attività nel file manifest per sovrascrivere il normale comportamento di abbattere e ricostruire l'attività. Tutto ciò, ovviamente, presuppone che l'applicazione possa determinare "quando" viene distrutta in modo che i dati possano essere mantenuti.
Dave

Risposte:


134

Non penso che 500kb sarà un grosso problema.

Quello che hai descritto è esattamente come ho affrontato il mio problema di perdita di dati in un'attività. Ho creato un singleton globale nella classe Application e sono stato in grado di accedervi dalle attività che ho usato.

Puoi passare i dati in un singleton globale se verrà utilizzato molto.

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

Quindi chiamalo in qualsiasi attività:

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

Ne discuto qui nel mio post sul blog , nella sezione "Global Singleton".


1
Purtroppo il post del blog in questione non è più disponibile a quell'indirizzo.
mikebabcock

1
Ho spostato cose sul mio sito. Fino a quando non viene risolto, puoi trovarlo su archive.org qui: web.archive.org/web/20130818035631/http://www.bryandenny.com/…
Bryan Denny

1
so che questo è un vecchio post ma mi sono appena imbattuto in un problema che potrebbe risolvere, tuttavia questa classe deve essere dichiarata in qualche modo nel manifest, no? non posso acsses la classe in modo da sentire come questo è quello che mi manca ...
Ziv Kesten

1
@ZivKesten Che ne dici di aggiungere l'attributo name = al tag dell'applicazione all'interno del manifest?
MikeC

@mgc grazie è passato un po 'di tempo, e sì, è così che alla fine l'ho risolto, inoltre ho creato istanze di quella classe ovunque ne avessi bisogno dandogli getApplicationContext () con un cast a questa classe
Ziv Kesten

57

Coloro che contano Applicationsull'istanza hanno torto. All'inizio, può sembrare che Applicationesista finché esiste l'intero processo dell'app, ma questo è un presupposto errato.

Il sistema operativo può terminare i processi se necessario. Tutti i processi sono suddivisi in 5 livelli di "killability" specificati nel doc .

Quindi, ad esempio, se la tua app va in background a causa dell'utente che risponde a una chiamata in arrivo, a seconda dello stato della RAM, il sistema operativo potrebbe (o meno) uccidere il tuo processo (distruggendo l' Applicationistanza nel processo) .

Penso che un approccio migliore sarebbe quello di conservare i tuoi dati nel file di archiviazione interno e poi leggerlo quando riprende la tua attività.

AGGIORNARE:

Ho ricevuto molti feedback negativi, quindi è ora di aggiungere una precisazione. :) Beh, inizialmente ho usato davvero l'ipotesi sbagliata che lo stato sia davvero importante per l'app. Tuttavia, se la tua app è OK a volte lo stato viene perso (potrebbero essere alcune immagini che verranno semplicemente rilette / scaricate di nuovo), allora è del tutto OK mantenerlo come membro di Application.


14
Se l'applicazione viene interrotta, chi se ne frega, giusto? L'applicazione è andata. A quanto ho capito, Android recupererà i processi che contengono memoria come le attività. Se il processo contenente l'applicazione viene interrotto (se Android lo farà?), È essenzialmente come uccidere l'app. L'utente dovrà riavviare l'app e, a quel punto, chi se ne frega? È una nuova istanza dell'applicazione.
Andrew

14
Questa è stata una brutta sorpresa per noi in produzione. Credimi, Android uccide i processi, dipende solo dallo stato della RAM e da altri fattori descritti nella documentazione. È stato un incubo per noi, quindi condivido la mia vera esperienza. Beh, non lo avevamo sugli emulatori, ma nel mondo reale alcuni dispositivi sono "sovraccarichi" di app, quindi uccidere un processo in background è una situazione normale. Sì, se l'utente decide quindi di mettere l'app in primo piano, il sistema operativo ripristina il suo stack inclusa l' Applicationistanza, tuttavia non ci saranno i tuoi dati statici su cui contare a meno che tu non li abbia persistiti.
Vit Khudenko

2
Penso che probabilmente userò un approccio ibrido. Conoscevo già il trucco manifest per ignorare il cambio di orientamento (che ha altri vantaggi). Poiché l'applicazione è un gioco, non sono sicuro che persistere i dati tra i lanci sia abbastanza "importante"; anche se probabilmente non sarebbe terribilmente difficile in quanto la maggior parte dei dati può essere serializzata (anche se non vorrei serializzare e deserializzare tra ogni cambio di orientamento). Apprezzo decisamente l'input. Non direi che quelli che dipendono dall'istanza dell'app sono "sbagliati". Molto dipende dall'app :).
Dave

1
@Arhimed stai generalizzando troppo la tua risposta. E suggerendo un approccio ristretto basato sulla tua ipotesi. Falso presupposto: i dati contenuti nelle variabili statiche devono essere conservati in modo persistente tra le sessioni dell'app. Potrebbero esserci numerosi casi d'uso in cui i dati sono banali e non devono essere resi persistenti immediatamente.
Mandar Limaye

2
Ho circa 1 MB di dati con una struttura complicata. Serializzare / deserializzare può costare fino a 2-3 secondi quando il dispositivo è sovraccarico di lavoro. L'idea di risparmiare / caricare tra le attività costa troppo tempo. Uso l'applicazione come archivio. Ovviamente la mia classe di dati memorizzata nell'istanza dell'applicazione deve controllare ogni metodo: i dati sono ancora attivi o devono essere caricati. Quindi Dave deve: 1. fornire funzioni di caricamento / salvataggio 2. mantenere i dati nell'applicazione. 3. Tripla logica di controllo per l'accesso ai dati.
Kostadin

6

Se vuoi accedere al "Singleton globale" al di fuori di un'attività e non vuoi passare Contextattraverso tutti gli oggetti coinvolti per ottenere il singleton, puoi semplicemente definire un attributo statico nella tua classe dell'applicazione, che contiene il riferimento a si. Basta inizializzare l'attributo nel onCreate()metodo.

Per esempio:

public class ApplicationController extends Application {
    private static ApplicationController _appCtrl;

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

Perché sottoclassi di Application possono ottenere le risorse, è possibile accedervi semplicemente quando si definisce un metodo statico, che le restituisce, come:

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

Ma fai molta attenzione quando passi i riferimenti al contesto per evitare perdite di memoria .


6
Hai dimenticato di notare che devi aggiungere l'attributo xml android: name = ". ApplicationController" al tag dell'applicazione nel tuo manifest per creare un'istanza della classe.
eggie5

In realtà non è necessario estendere Applicationper farlo. È possibile dichiarare una variabile membro statica in qualsiasi classe per eseguire questa operazione.
David Wasser

2

Dave, che tipo di dati sono? Se sono dati generali che riguardano l'applicazione nel suo insieme (esempio: dati utente), estendi la classe Application e memorizzala lì. Se i dati riguardano l'attività, è necessario utilizzare i gestori onSaveInstanceState e onRestoreInstanceState per rendere persistenti i dati durante la rotazione dello schermo.


E se i dati fossero davvero grandi da archiviare in un pacco? Questo è ciò che sto ottenendo: android.os.TransactionTooLargeException: dimensione del pacchetto di dati 838396 byte
Arjun Issar

1

Puoi effettivamente ignorare la funzionalità di orientamento per assicurarti che la tua attività non venga distrutta e ricreata. Guarda qui .


16
Puoi fare molte cose. Non significa che siano buone idee. Questa non è una buona idea.
Andrew

Il test modificando l'orientamento dello schermo è il modo più semplice per assicurarti che la tua app faccia ciò che Android presume che faccia.
18446744073709551615

0

Puoi creare la classe Application e salvare tutti i tuoi dati su quel calss per usarli ovunque nella tua applicazione.


0

So che questa è la domanda molto vecchia, ma l'utilizzo del ViewModel dai componenti jetpack è il modo migliore per preservare i dati tra la rotazione delle attività.

La classe ViewModel è progettata per archiviare e gestire i dati relativi all'interfaccia utente in modo consapevole del ciclo di vita. La classe ViewModel consente ai dati di sopravvivere a modifiche di configurazione come le rotazioni dello schermo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.