risposta-alla-domanda-sullo-sviluppo-web-bd.com

Contesto Singletons vs. Application in Android?

Ricordando questo post che enumera diversi problemi di utilizzo dei singleton e avendo visto diversi esempi di applicazioni Android che usano il pattern singleton, mi chiedo se sia una buona idea usare invece Singletons di istanze singole condivise attraverso lo stato di applicazione globale (sottoclasse Android.os.Application e ottenerlo tramite context.getApplication ()).

Quali vantaggi/inconvenienti avrebbero entrambi i meccanismi?

Per essere onesti, mi aspetto la stessa risposta in questo post modello Singleton con l'applicazione Web, non una buona idea! ma applicata ad Android. Ho ragione? Cosa c'è di diverso in DalvikVM altrimenti?

EDIT: vorrei avere opinioni su diversi aspetti coinvolti:

  • Sincronizzazione
  • Riutilizzabilità
  • Analisi
356
mschonaker

Non sono affatto d'accordo con la risposta di Dianne Hackborn. A poco a poco stiamo rimuovendo tutti i singleton dal nostro progetto a favore di oggetti con ambito di lavoro leggero, che possono essere facilmente ricreati quando ne hai effettivamente bisogno.

I singleton sono un incubo per i test e, se pigramente inizializzati, introdurranno "indeterminism state" con effetti secondari lievi (che possono improvvisamente emergere quando si spostano le chiamate a getInstance() da un ambito ad un altro). La visibilità è stata menzionata come un altro problema, e dal momento che i singleton implicano accesso "globale" (= casuale) allo stato condiviso, possono insorgere bug sottili quando non correttamente sincronizzati in applicazioni concorrenti.

Lo considero un anti-pattern, è un cattivo stile orientato agli oggetti che essenzialmente equivale a mantenere lo stato globale.

Per tornare alla tua domanda:

Sebbene il contesto dell'app possa essere considerato singleton, è gestito dal framework e ha un ciclo di vita , ambito e accesso ben definito . Quindi credo che se hai bisogno di gestire lo stato globale dell'app, dovrebbe andare qui, da nessun'altra parte. Per qualsiasi altra cosa, ripensate se avete (===) realmente bisogno di un oggetto singleton, o se sarebbe anche possibile riscrivere la vostra classe singleton per istanziare piccoli oggetti di breve durata che eseguono il compito a portata di mano .

291
Matthias

Raccomando molto singleton. Se hai un singleton che ha bisogno di un contesto, hai:

MySingleton.getInstance(Context c) {
    //
    // ... needing to create ...
    sInstance = new MySingleton(c.getApplicationContext());
}

Preferisco i single su Application perché aiuta a mantenere un'app molto più organizzata e modulare - invece di avere uno spazio in cui è necessario mantenere tutto lo stato globale dell'applicazione, ogni singolo elemento può prendersi cura di se stesso. Anche il fatto che i singletons inizializzino pigramente (su richiesta) invece di guidarvi lungo il percorso di fare tutte le inizializzazioni in anticipo in Application.onCreate () è buono.

Non c'è nulla di intrinsecamente sbagliato nell'usare i singleton. Basta usarli correttamente, quando ha senso. Il framework Android in realtà ne ha molti, perché mantiene le cache per processo di risorse caricate e altre cose simili.

Anche per le applicazioni semplici il multithreading non diventa un problema con i singleton, perché in base alla progettazione tutti i callback standard dell'app vengono inviati sul thread principale del processo in modo che non si verifichi il multithreading a meno che non lo si introduca esplicitamente tramite thread o implicitamente pubblicando un fornitore di contenuti o un servizio IBinder ad altri processi.

Pensa solo a quello che stai facendo. :)

226
hackbod

Da: Sviluppatore> riferimento - Applicazione

Di norma non c'è bisogno di sottoclasse l'applicazione. Nella maggior parte dei casi, i singleton statici possono fornire la stessa funzionalità in un modo più modulare. Se il singleton ha bisogno di un contesto globale (ad esempio per registrare ricevitori broadcast), la funzione per recuperarlo può avere un contesto che utilizza internamente Context.getApplicationContext () quando si costruisce il singleton.

20
Somatik

Ho avuto lo stesso problema: Singleton o creare una sottoclasse Android.os.Application?

Per prima cosa ho provato con Singleton ma la mia app ad un certo punto effettua una chiamata al browser

Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));

e il problema è che, se il portatile non ha abbastanza memoria, la maggior parte delle tue classi (anche Singletons) vengono pulite per ottenere un po 'di memoria, così, quando ritorna dal browser alla mia app, si blocca ogni volta.

Soluzione: inserire i dati necessari in una sottoclasse di classe Application.

11
JoséMi

L'applicazione non è la stessa di Singleton. I motivi sono:

  1. Il metodo dell'applicazione (come onCreate) è chiamato nel thread ui;
  2. il metodo di singleton può essere chiamato in qualsiasi thread;
  3. Nel metodo "onCreate" di Application, puoi istanziare Handler;
  4. Se il singleton viene eseguito nel thread none-ui, non è possibile istanziare Handler;
  5. L'applicazione ha la capacità di gestire il ciclo di vita delle attività nell'app. Ha il metodo "registerActivityLifecycleCallbacks". Ma i singleton non ne hanno l'abilità.
10
sunhang

Considera entrambi allo stesso tempo:

  • avere oggetti singleton come istanze statiche all'interno delle classi.
  • avendo una classe comune (Context) che restituisce le istanze singleton per tutti gli oggetti singelton nell'applicazione, che presenta il vantaggio che i nomi dei metodi in Context saranno significativi, ad esempio: context.getLoggedinUser () anziché User.getInstance ().

Inoltre, ti suggerisco di espandere il tuo Contesto per includere non solo l'accesso agli oggetti singleton ma alcune funzionalità a cui è necessario accedere globalmente, come ad esempio: context.logOffUser (), context.readSavedData (), ecc. Probabilmente rinominando il Context in La facciata avrebbe senso allora.

5
adranale

In realtà sono uguali. C'è una differenza che posso vedere. Con la classe Application puoi inizializzare le tue variabili in Application.onCreate () e distruggerle in Application.onTerminate (). Con singleton devi contare VM inizializzando e distruggendo la statica.

4
Fedor

Dalla bocca del proverbiale cavallo ...

Quando sviluppi la tua app, potresti trovare necessario condividere dati, contesto o servizi a livello globale attraverso la tua app. Ad esempio, se la tua app ha dati di sessione, come l'utente attualmente loggato, probabilmente vorrai esporre queste informazioni. In Android, il modello per risolvere questo problema è quello di avere l'istanza di Android.app.Application possedere tutti i dati globali e quindi considerare l'istanza dell'applicazione come un singleton con accessor statici ai vari dati e servizi.

Quando scrivi un'app per Android, hai la garanzia di avere solo un'istanza della classe Android.app.Application, quindi è sicuro (e consigliato dal team di Google Android) di considerarlo un singleton. Cioè, puoi tranquillamente aggiungere un metodo getInstance () statico all'implementazione dell'applicazione. Così:

public class AndroidApplication extends Application {

    private static AndroidApplication sInstance;

    public static AndroidApplication getInstance(){
        return sInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sInstance = this;
    }
}
3
RMcGuigan

I miei 2 centesimi:

Ho notato che alcuni campi singleton/statici sono stati resettati quando la mia attività è stata distrutta. Ho notato questo su alcuni dispositivi di fascia bassa 2.3.

Il mio caso era molto semplice: ho solo un file privato "init_done" e un metodo statico "init" che ho chiamato da activity.onCreate (). Ho notato che il metodo init si stava rieseguendo da solo su alcune ricreazioni dell'attività.

Anche se non riesco a dimostrare la mia affermazione, potrebbe essere correlato a QUANDO il singleton/classe è stato creato/utilizzato per primo. Quando l'attività viene distrutta/riciclata, sembra che tutte le classi a cui si riferisce solo questa attività siano anch'esse riciclate.

Ho spostato la mia istanza di singleton in una sottoclasse di applicazioni. Li accedo dall'istanza dell'applicazione. e, da allora, non si è più accorto del problema.

Spero che questo possa aiutare qualcuno.

3
Christ

La mia attività chiama finish () (che non finisce immediatamente, ma lo farà alla fine) e chiama Google Street Viewer. Quando eseguo il debug su Eclipse, la mia connessione all'app si interrompe quando viene chiamato Street Viewer, che capisco quando l'applicazione (completa) viene chiusa, presumibilmente per liberare memoria (poiché una singola attività terminata non dovrebbe causare questo comportamento) . Tuttavia, sono in grado di salvare lo stato in un pacchetto tramite onSaveInstanceState () e ripristinarlo nel metodo onCreate () della prossima attività nello stack. O utilizzando un oggetto Singleton statico o una sottoclassi Application I affrontare lo stato di chiusura e di perdita dell'applicazione (a meno che non lo salvi in ​​un pacchetto). Quindi dalla mia esperienza sono uguali per quanto riguarda la conservazione dello stato. Ho notato che la connessione si perde in Android 4.1.2 e 4.2.2 ma non in 4.0.7 o 3.2.4, il che a mio avviso suggerisce che il meccanismo di recupero della memoria è cambiato a un certo punto.

2
Piovezan