Quando chiamare il contesto dell'attività O il contesto dell'applicazione?


265

Ci sono stati molti post su cosa sono questi due contesti .. Ma non riesco ancora a capire bene

A quanto ho capito finora: ognuno è un'istanza della sua classe, il che significa che alcuni programmatori ti raccomandano di usare il this.getApplicationContext()più spesso possibile per non "perdere" memoria. Questo perché l'altro this(ottenendo il Activitycontesto dell'istanza) indica un elemento Activityche viene distrutto ogni volta che l'utente inclina il telefono o lascia l'app ecc. Che apparentemente il Garbage Collector (GC) non rileva e quindi utilizza troppa memoria ..

Qualcuno può, per favore, fornire alcuni esempi di codifica davvero buoni in cui sarebbe la cosa giusta da usare this(ottenere il contesto Activitydell'istanza corrente ) e il contesto dell'applicazione sarà inutile / sbagliato?

Risposte:


408

getApplicationContext()è quasi sempre sbagliato. Ms. Hackborn (tra gli altri) sono stati molto esplicito che solo utilizzare getApplicationContext()quando si sa il motivo per cui si sta utilizzando getApplicationContext()e solo quando si ha bisogno di usare getApplicationContext().

Ad essere sinceri, "alcuni programmatori" usano getApplicationContext()(o getBaseContext(), in misura minore) perché la loro esperienza Java è limitata. Implementano una classe interna (es. An OnClickListenerper a Buttonin an Activity) e hanno bisogno di a Context. Anziché utilizzare MyActivity.thisper accedere alla classe esterna " this, usano getApplicationContext()o getBaseContext()per ottenere un Contextoggetto.

È solo utilizzare getApplicationContext()quando si sa hai bisogno di un Contextqualcosa che può vivere più a lungo di qualsiasi altro probabilmente Contextavete a vostra disposizione. Gli scenari includono:

  • Usa getApplicationContext()se hai bisogno di qualcosa legato a un oggetto Contextche avrà un ambito globale. Uso getApplicationContext(), ad esempio, in WakefulIntentService, per l'elettricità statica WakeLockda utilizzare per il servizio. Dal momento che WakeLockè statico e ho bisogno di un Contextper arrivare a PowerManagercrearlo, è più sicuro da usare getApplicationContext().

  • Utilizzare getApplicationContext()quando si esegue il binding a a Serviceda an Activity, se si desidera passare il ServiceConnection(ovvero, la maniglia al binding) tra Activityistanze tramite onRetainNonConfigurationInstance(). Android traccia internamente i binding tramite questi ServiceConnectionse contiene riferimenti a quelli Contextsche creano i binding. Se si esegue il binding da Activity, quindi la nuova Activityistanza avrà un riferimento a quello ServiceConnectionche ha un riferimento implicito al vecchio Activitye il vecchio Activitynon può essere raccolto.

Alcuni sviluppatori utilizzano sottoclassi personalizzate Applicationper i propri dati globali, tramite i quali recuperano getApplicationContext(). Questo è certamente possibile. Preferisco i membri di dati statici, se non altro per il motivo che puoi avere un solo Applicationoggetto personalizzato . Ho creato un'app usando un Applicationoggetto personalizzato e l'ho trovata dolorosa. Anche la sig.ra Hackborn è d'accordo con questa posizione .

Ecco i motivi per cui non utilizzare getApplicationContext()ovunque tu vada:

  • Non è completo Context, supporta tutto ciò che Activityfa. Varie cose che proverai a fare con questo Contextfalliranno, principalmente legate alla GUI .

  • Può creare perdite di memoria, se il Contextda si getApplicationContext()attacca a qualcosa creato dalle tue chiamate su di esso che non ripulisci. Con un Activity, se si tiene su qualcosa, una volta che la Activityspazzatura viene raccolta, anche tutto il resto viene scaricato. L' Applicationoggetto rimane per tutta la durata del processo.


1
Grazie mille per questa risposta Un altro link che ho trovato prima di leggere questa risposta potrebbe anche aiutare alcune persone. stackoverflow.com/questions/7298731/… - questo link spiega le mie preoccupazioni riguardo alla perdita di memoria.
Norfeldt,

27
@Norfeldt: Cordiali saluti, il link nel tuo commento rimanda a questa risposta.
Commons War

2
grazie .. questo era il link: stackoverflow.com/questions/5796611/… descrive la perdita di memoria che avevo paura di ottenere usando questo
Norfeldt,

6
@djaqeel: l'ultima parte del tuo preventivo è quasi vera. È meglio espresso come "non dare un contesto di attività a qualcosa che vivrà più a lungo di quanto non farà l'attività, come un membro di dati statici". Tuttavia, usi ancora solo getApplicationContext()quando sai esattamente perché ne hai bisogno in una determinata situazione. Gonfiare un layout? Usa l'attività. Associazione a un servizio, dove è necessario tale associazione per sopravvivere a una modifica della configurazione? Utilizzare getApplicationContext(), quindi l'associazione non è legata Activityall'istanza.
Commons War

7
@Sever: lo copro nella mia risposta. Dave Smith ha anche un eccellente post sul blog che copre i contesti: doubleencore.com/2013/06/context Il suo paragrafo di riepilogo: "Nella maggior parte dei casi, usa il Contesto direttamente a tua disposizione dal componente allegato in cui lavori. un riferimento a condizione che tale riferimento non si estenda oltre il ciclo di vita di quel componente. Non appena è necessario salvare un riferimento a un contesto da un oggetto che si trova al di là della propria attività o servizio, anche temporaneamente, passare a quel riferimento che si salva nel contesto dell'applicazione ".
CommonsWare,

48

Penso che ci siano molte cose che sono scarsamente documentate sul sito dell'SDK, questa è una di queste. L'affermazione che farò è che sembra che per impostazione predefinita sia meglio usare un contesto di applicazione e usare un contesto di attività solo quando è veramente necessario. L'unico posto in cui ho mai visto che hai bisogno di un contesto di attività è una finestra di dialogo sullo stato di avanzamento. SBERG412 afferma che è necessario utilizzare un contesto di attività per un messaggio di brindisi, ma i documenti Android mostrano chiaramente un contesto di applicazione in uso. Ho sempre usato il contesto dell'applicazione per i brindisi grazie a questo esempio di Google. Se è sbagliato farlo, Google ha lasciato cadere la palla qui.

Ecco altro su cui riflettere e rivedere:

Per un messaggio di brindisi, la Guida di Dev di Google utilizza il contesto dell'applicazione e dice esplicitamente di usarlo: Notifiche di brindisi

Nella sezione finestre di dialogo della guida per sviluppatori, vedi che AlertDialog.Builder utilizza il contesto dell'applicazione, quindi la barra di avanzamento utilizza un contesto di attività. Questo non è spiegato da Google. Finestre di dialogo

Sembra che un buon motivo per utilizzare il contesto dell'applicazione sia quando si desidera gestire le modifiche alla configurazione come una modifica dell'orientamento e si desidera conservare gli oggetti che richiedono un contesto come Viste. Se si guarda qui: modifiche al tempo di esecuzione Vi è una avvertenza sull'uso di un contesto di attività, che può creare una perdita. Questo può essere evitato con un contesto applicativo con le viste che devono essere mantenute (almeno questa è la mia comprensione). In un'app che sto scrivendo, intendo utilizzare un contesto di applicazione perché sto cercando di conservare alcune viste e altre cose su un cambiamento di orientamento, e voglio ancora che l'attività venga distrutta e ricreata sui cambiamenti di orientamento. Quindi devo usare un contesto di app per non causare una perdita di memoria (vedi Come evitare perdite di memoria). A me sembra che ci siano molte buone ragioni per usare il contesto dell'applicazione invece di un contesto di attività, e per me sembra quasi che lo useresti più spesso di un contesto di attività. Questo è ciò che molti libri Android che ho passato sembrano fare, ed è quello che fanno molti degli esempi di Google che ho visto.

La documentazione di Google sembra davvero che l'uso del contesto dell'applicazione sia perfettamente corretto nella maggior parte dei casi, e in effetti appare più spesso rispetto all'utilizzo di un contesto di attività nei loro esempi (almeno gli esempi che ho visto). Se è davvero un problema utilizzare il contesto dell'applicazione, Google deve davvero porre maggiormente l'accento su questo. Devono chiarire e devono rifare alcuni dei loro esempi. Non darei la colpa interamente a sviluppatori inesperti poiché l'autorità (Google) fa davvero sembrare che non sia un problema usare contesti applicativi.


5
Sono completamente d'accordo. La risposta di CommonsWare è stata una sorpresa per me. Sono contento di aver trovato questa domanda, perché la documentazione di Google suggerisce che l'utilizzo di getApplicationContext può essere così pericoloso.
Steve Schwarcz,

38

Ho usato questa tabella come guida per quando usare i diversi tipi di contesto come il contesto dell'applicazione (es .::) getApplicationContext()e il contesto dell'attività , anche il contesto BroadcastReceiver :

inserisci qui la descrizione dell'immagine

Tutti i meriti vanno all'autore originale qui per maggiori informazioni.


11

Quale contesto usare?

Esistono due tipi di contesto:

  1. Il contesto dell'applicazione è associato all'applicazione e sarà sempre lo stesso per tutta la durata dell'applicazione - non cambia. Quindi, se si utilizza Toast, è possibile utilizzare il contesto dell'applicazione o anche il contesto dell'attività (entrambi) perché toast può essere visualizzato da qualsiasi punto dell'applicazione e non è collegato a una finestra specifica. Ma ci sono molte eccezioni, un'eccezione è quando è necessario utilizzare o passare il contesto dell'attività.

  2. Il contesto dell'attività è associato all'attività e può essere distrutto se l'attività viene distrutta: potrebbero esserci più attività (più che probabile) con una singola applicazione. E a volte hai assolutamente bisogno della gestione del contesto di attività. Ad esempio, se si avvia una nuova attività, è necessario utilizzare il contesto dell'attività nelle sue intenzioni in modo che la nuova attività di avvio sia connessa all'attività corrente in termini di stack di attività. Tuttavia, è possibile utilizzare anche il contesto dell'applicazione per avviare una nuova attività, ma è necessario impostare il flag Intent.FLAG_ACTIVITY_NEW_TASKnell'intento di trattarlo come una nuova attività.

Consideriamo alcuni casi:

  • MainActivity.this si riferisce al contesto MainActivity che estende la classe Activity ma la classe base (attività) estende anche la classe Context, quindi può essere utilizzata per offrire il contesto dell'attività.

  • getBaseContext() offre contesto di attività.

  • getApplication() offre il contesto dell'applicazione.

  • getApplicationContext() offre anche un contesto applicativo.

Per ulteriori informazioni, consultare questo link .


Che dire del caso in cui è necessario visualizzare un AlertDialog nell'app ad es. Un processo asincrono che mostra un risultato. Un esempio di ciò può essere : l'utente fa clic sul download, questo attiva una richiesta di download downloadmanagere, quando viene ricevuto il segnale finito, dovrebbe mostrare una finestra di dialogo, ad esempio "Cosa vuoi fare con questo download?". La mia soluzione (hack) salva la più recente Activityin una static Applicationclasse e richiede la corrente al Activitytermine del download. Tuttavia, dubito che questa sia la corretta attuazione. TL; DR Come visualizzare AlertDialog ovunque nell'app?
CybeX,

@KGCybeX Se si desidera visualizzare qualsiasi cosa e ovunque nella propria app al termine del download, è necessario registrare manualmente un ricevitore di trasmissione sull'attività che ascolta un messaggio specifico che il servizio di download trasmetterà e fare ciò che si desidera alla ricezione del messaggio o allegare la tua attività direttamente a quel servizio.
ExiRouS,

6

Mi chiedevo perché non usare il contesto dell'applicazione per ogni operazione che supporta. Alla fine riduce la possibilità di perdita di memoria e il controllo null mancante per getContext () o getActivity () (quando si utilizza il contesto dell'applicazione iniettato o acquisito tramite il metodo statico dall'applicazione). Dichiarazioni, come quella della sig.ra Hackborn di utilizzare il contesto applicativo solo se necessario, non mi sembrano convincenti senza una spiegazione del perché. Ma sembra che ho trovato un indumenti intimi perché:

hanno riscontrato problemi in alcune combinazioni di versione / dispositivo Android che non seguono queste regole. Ad esempio, se ho un BroadcastReceiver a cui viene passato un contesto e lo converto in un contesto dell'applicazione e quindi provo a chiamare registerReceiver () nel contesto dell'applicazione, ci sono molti casi in cui funziona bene, ma anche molti casi in cui ottengo un arresto anomalo a causa di ReceiverCallNotAllowedException. Questi arresti anomali si verificano su una vasta gamma di versioni di Android dall'API 15 al 22. https://possiblemobile.com/2013/06/context/#comment-2443283153

Perché non è garantito che tutte le operazioni descritte come supportate dal contesto dell'applicazione nella tabella seguente funzionino su tutti i dispositivi Android! inserisci qui la descrizione dell'immagine


4

Due grandi esempi di quando dovresti usare il contesto Activity rispetto al contesto Application sono quando visualizzi un messaggio Toast o un messaggio Dialog incorporato poiché l'uso del contesto Application causerà un'eccezione:

ProgressDialog.show(this, ....);

o

Toast t = Toast.makeText(this,....);

Entrambi richiedono informazioni dal contesto Activity che non sono fornite nel contesto Application.


5
Hm .. Quale versione del sistema operativo Android hai testato? Ho provato il 4.4.4 e funziona bene. Inoltre, come menzionato da @Andi Jay, il documento ufficiale per sviluppatori Android ha utilizzato il contesto dell'applicazione nel loro codice di esempio. developer.android.com/guide/topics/ui/notifiers/…
김준호

1
@ Nome cinese, sì, potrebbe funzionare ma a volte nel futuro di quell'app, si bloccherà anche. Mi è successo più volte.
Ojonugwa Jude Ochalifu,

1
Quando utilizzo il contesto Attività in Toast, perde memoria!
Jemshit Iskenderov,

3

Contesto applicativo in diretta fino a vostra applicazione è vivo solo ed è non dipende da attività del ciclo di vita, ma, il contesto oggetto mantenere a lungo vissuto . Se l'oggetto che si utilizza temporaneamente, quella volta si utilizza Contesto applicazione e Contesto attività viene utilizzato totalmente opposto a Contesto applicazione.

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.