Ho scritto questa risposta nel '09, quando Android era relativamente nuovo e c'erano molte aree non ben consolidate nello sviluppo di Android. Ho aggiunto un lungo addendum in fondo a questo post, affrontando alcune critiche e descrivendo in dettaglio un disaccordo filosofico che ho con l'uso di Singletons piuttosto che con la sottoclasse Application. Leggilo a tuo rischio e pericolo.
RISPOSTA ORIGINALE:
Il problema più generale che stai riscontrando è come salvare lo stato in diverse attività e in tutte le parti dell'applicazione. Una variabile statica (ad esempio un singleton) è un modo Java comune per raggiungere questo obiettivo. Ho scoperto, tuttavia, che un modo più elegante in Android è associare il tuo stato al contesto dell'applicazione.
Come sapete, ogni attività è anche un contesto, ovvero informazioni sul suo ambiente di esecuzione in senso lato. La tua applicazione ha anche un contesto e Android garantisce che esisterà come una singola istanza in tutta l'applicazione.
Il modo per farlo è creare la tua sottoclasse di android.app.Application e quindi specificare quella classe nel tag dell'applicazione nel manifest. Ora Android creerà automaticamente un'istanza di quella classe e la renderà disponibile per l'intera applicazione. È possibile accedervi da qualsiasi context
utilizzo del Context.getApplicationContext()
metodo ( Activity
fornisce anche un metodo getApplication()
che ha lo stesso effetto esatto). Di seguito è riportato un esempio estremamente semplificato, con le avvertenze da seguire:
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();
...
}
}
Questo ha essenzialmente lo stesso effetto dell'utilizzo di una variabile statica o singleton, ma si integra abbastanza bene nel framework Android esistente. Tieni presente che questo non funzionerà tra i processi (se la tua app è una delle rare che ha più processi).
Qualcosa da notare dall'esempio sopra; supponiamo di aver invece fatto qualcosa del tipo:
class MyApp extends Application {
private String myState = /* complicated and slow initialization */;
public String getState(){
return myState;
}
}
Ora questa lenta inizializzazione (come colpire il disco, colpire la rete, qualsiasi blocco, ecc.) Verrà eseguita ogni volta che l'applicazione viene istanziata! Potresti pensare, beh, questo è solo una volta per il processo e dovrò comunque pagare il costo, giusto? Ad esempio, come indicato di seguito da Dianne Hackborn, è del tutto possibile che il processo venga istanziato -solo- per gestire un evento di trasmissione in background. Se l'elaborazione della trasmissione non ha bisogno di questo stato, potenzialmente hai appena fatto un'intera serie di operazioni complicate e lente per niente. Un'istanza pigra è il nome del gioco qui. Di seguito è riportato un modo leggermente più complicato di utilizzare l'applicazione che ha più senso per qualsiasi cosa tranne che per gli usi più semplici:
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();
...
}
}
Mentre preferisco la sottoclasse delle applicazioni all'utilizzo dei singleton qui come soluzione più elegante, preferirei che gli sviluppatori usassero i singleton se davvero necessari piuttosto che non pensare affatto attraverso le prestazioni e le implicazioni multithreading di associare lo stato alla sottoclasse Application.
NOTA 1: anche come commentato anticafe, per legare correttamente la sostituzione dell'applicazione alla propria applicazione è necessario un tag nel file manifest. Ancora una volta, consulta i documenti Android per ulteriori informazioni. Un esempio:
<application
android:name="my.application.MyApp"
android:icon="..."
android:label="...">
</application>
NOTA 2: user608578 chiede di seguito come funziona con la gestione dei cicli di vita degli oggetti nativi. Non sono minimamente in grado di utilizzare il codice nativo con Android e non sono qualificato per rispondere a come interagirebbe con la mia soluzione. Se qualcuno ha una risposta a questo, sono disposto ad accreditarli e mettere le informazioni in questo post per la massima visibilità.
APPENDICE:
Come alcune persone hanno notato, questa non è una soluzione per lo stato persistente , qualcosa che forse avrei dovuto sottolineare maggiormente nella risposta originale. Vale a dire che non si intende che sia una soluzione per il salvataggio di utenti o altre informazioni che devono essere mantenute per tutta la vita delle applicazioni. Pertanto, ritengo che la maggior parte delle critiche riportate di seguito riguardino il fatto che le applicazioni vengano uccise in qualsiasi momento, ecc ..., discutendo, poiché tutto ciò che è mai stato necessario perseverare su disco non dovrebbe essere archiviato attraverso una sottoclasse dell'applicazione. È pensato per essere una soluzione per la memorizzazione di uno stato di applicazione temporaneo e facilmente ricreabile (ad esempio se un utente ha effettuato l'accesso) e componenti che sono di singola istanza (ad esempio gestore della rete di applicazione) ( NON singleton!) In natura.
Dayerman è stato così gentile da segnalare un'interessante conversazione con Reto Meier e Dianne Hackborn in cui l'uso delle sottoclassi delle applicazioni è scoraggiato a favore dei modelli Singleton. Somatik ha anche sottolineato qualcosa di simile in precedenza, anche se non l'ho visto al momento. A causa dei ruoli di Reto e Dianne nel mantenimento della piattaforma Android, non posso in buona fede raccomandare di ignorare i loro consigli. Quello che dicono, va. Desidero essere in disaccordo con le opinioni espresse in merito alla preferenza per le sottoclassi delle applicazioni Singleton. Nel mio disaccordo userò i concetti meglio spiegati in questa spiegazione StackExchange del modello di progettazione Singleton, quindi non devo definire i termini in questa risposta. Consiglio vivamente di scremare il link prima di continuare. Punto per punto:
Dianne afferma: "Non c'è motivo di sottoclassare dall'Applicazione. Non è diverso dal creare un singleton ..." Questa prima affermazione non è corretta. Ci sono due ragioni principali per questo. 1) La classe Application offre una migliore garanzia a vita per uno sviluppatore di applicazioni; è garantito che abbia la durata dell'applicazione. Un singleton non è ESPLICITAMENTE legato alla durata dell'applicazione (sebbene sia efficace). Questo potrebbe non essere un problema per il tuo sviluppatore medio di applicazioni, ma direi che questo è esattamente il tipo di contratto che dovrebbe essere offerto dall'API Android e fornisce anche molta più flessibilità al sistema Android, riducendo al minimo la durata degli associati dati. 2) La classe Application fornisce allo sviluppatore dell'applicazione un unico proprietario di istanza per stato, che è molto diverso da un detentore di stato Singleton. Per un elenco delle differenze, vedere il link di spiegazione Singleton sopra.
Dianne continua, "... probabilmente sarà qualcosa di cui ti pentirai in futuro quando scoprirai che il tuo oggetto Application sta diventando questo grande pasticcio di ciò che dovrebbe essere una logica applicativa indipendente." Questo non è certamente errato, ma non è un motivo per scegliere la sottoclasse Singleton su Applicazione. Nessuno degli argomenti di Diane fornisce una ragione per cui usare una Singleton sia meglio di una sottoclasse di Applicazione, tutto ciò che tenta di stabilire è che usare una Singleton non è peggio di una Sottoclasse di Applicazione, che credo sia falsa.
Continua, "E questo porta più naturalmente a come dovresti gestire queste cose - inizializzandole su richiesta." Ciò ignora il fatto che non esiste alcun motivo per cui non è possibile inizializzare su richiesta utilizzando anche una sottoclasse Applicazione. Ancora una volta non c'è differenza.
Dianne termina con "Il framework stesso ha tonnellate e tonnellate di singoli per tutti i piccoli dati condivisi che mantiene per l'app, come cache di risorse caricate, pool di oggetti, ecc. Funziona alla grande". Non sto sostenendo che l'uso di Singleton non possa funzionare bene o non sia un'alternativa legittima. Sto sostenendo che Singleton non fornisce un contratto così forte con il sistema Android come l'utilizzo di una sottoclasse di Applicazione, e inoltre che l'utilizzo di Singletons indica generalmente un design inflessibile, che non è facilmente modificabile, e porta a molti problemi lungo la strada. IMHO, il forte contratto che l'API Android offre alle applicazioni degli sviluppatori è uno degli aspetti più interessanti e piacevoli della programmazione con Android e ha contribuito a portare all'adozione anticipata degli sviluppatori che ha guidato la piattaforma Android verso il successo che ha oggi.
Dianne ha anche commentato di seguito, menzionando un ulteriore svantaggio dell'uso delle sottoclassi di applicazioni, che possono incoraggiare o semplificare la scrittura di un codice di prestazioni inferiore. Questo è molto vero e ho modificato questa risposta per sottolineare l'importanza di considerare perf qui e adottare l'approccio corretto se si utilizza la sottoclasse dell'applicazione. Come afferma Dianne, è importante ricordare che la tua classe Application verrà istanziata ogni volta che il tuo processo viene caricato (potrebbe essere più volte contemporaneamente se l'applicazione viene eseguita in più processi!) Anche se il processo viene caricato solo per una trasmissione in background evento. È quindi importante utilizzare la classe Application più come repository per puntatori a componenti condivisi della tua applicazione piuttosto che come luogo per eseguire qualsiasi elaborazione!
Vi lascio con il seguente elenco di aspetti negativi di Singletons, come rubato dal precedente link StackExchange:
- Incapacità di usare classi astratte o di interfaccia;
- Incapacità di sottoclasse;
- Elevato accoppiamento attraverso l'applicazione (difficile da modificare);
- Difficile da testare (impossibile falsificare / simulare nei test unitari);
- Difficile parallelizzare in caso di stato mutevole (richiede un blocco esteso);
e aggiungi il mio:
- Contratto a vita poco chiaro e ingestibile non adatto allo sviluppo di Android (o la maggior parte degli altri);