getApplication () vs. getApplicationContext ()


417

Non sono riuscito a trovare una risposta soddisfacente a questo, quindi eccoci qui: qual è il problema Activity/Service.getApplication()e Context.getApplicationContext()?

Nella nostra applicazione, entrambi restituiscono lo stesso oggetto. In un caso ActivityTestCase, deridere l'applicazione farà getApplication()tornare indietro con il finto, ma getApplicationContextrestituirà comunque un'istanza di contesto diversa (quella iniettata da Android). È un bug? È apposta?

Non capisco nemmeno la differenza in primo luogo. Esistono casi al di fuori di una suite di test in cui entrambe le chiamate possono tornare con oggetti diversi? Quando e perché? Inoltre, perché è getApplicationdefinito su Activitye Service, ma non su Context? Non dovrebbe sempre esserci un'istanza di applicazione valida disponibile da qualsiasi luogo ?


8
Bella domanda Il materiale di prova è un po 'un mistero (come ben sapete). Ma mi chiedo se si manifesta qualche differenza in queste due chiamate di metodo se non si crea esplicitamente un Applicationoggetto nella propria app.
Christopher Orr,

Risposte:


366

Domanda molto interessante. Penso che sia principalmente un significato semantico e potrebbe anche essere dovuto a ragioni storiche.

Sebbene nelle attuali implementazioni di attività e servizi Android getApplication()e getApplicationContext()restituisca lo stesso oggetto, non vi è alcuna garanzia che ciò avvenga sempre (ad esempio, in un'implementazione specifica del fornitore).

Quindi, se vuoi la classe Application che hai registrato nel Manifest, non dovresti mai chiamarla getApplicationContext()e lanciarla nella tua applicazione, perché potrebbe non essere l'istanza dell'applicazione (che ovviamente hai provato con il framework di test).

Perché getApplicationContext()esiste in primo luogo?

getApplication()è disponibile solo nella classe Activity e nella classe Service, mentre getApplicationContext()è dichiarato nella classe Context.

Questo in realtà significa una cosa: quando si scrive il codice in un ricevitore broadcast, che non è un contesto ma viene dato un contesto nel suo metodo onReceive, è possibile solo chiamare getApplicationContext(). Ciò significa anche che non è garantito l'accesso alla propria applicazione in un BroadcastReceiver.

Quando guardi il codice Android, vedi che quando è collegata, un'attività riceve un contesto di base e un'applicazione, e questi sono parametri diversi. getApplicationContext()delegati a cui è chiamata baseContext.getApplicationContext().

Ancora una cosa: la documentazione dice che nella maggior parte dei casi non è necessario sottoclassare l'Applicazione:

Normalmente non è necessario eseguire la sottoclasse Application. Nella maggior parte dei casi, i singoli statici possono fornire la stessa funzionalità in un modo più modulare. Se il tuo singleton ha bisogno di un contesto globale (ad esempio per registrare i ricevitori di trasmissione), la funzione per recuperarlo può essere assegnata a un oggetto Contextche utilizza internamente Context.getApplicationContext()durante la prima costruzione del singleton.

So che questa non è una risposta esatta e precisa, ma risponde alla tua domanda?


89
@ Piwaï: non ascoltare il documento. La sottoclasse android.app.Applicationè un super aiuto completo. Ad esempio ho avuto infiniti problemi durante l'inizializzazione del database. Una volta spostato in Application.onCreateesso ha funzionato come un fascino. Ora eseguo tutta l'inizializzazione del sistema Applicatione non scriverei un'altra app senza.
Martin,

9
@Martin Non ascoltare i documenti generalmente significa che il tuo codice potrebbe rompersi in futuro, o anche ora in condizioni impreviste, perdere la portabilità, comportarsi male, impedire agli sviluppatori di piattaforme di apportare una modifica benefica (che interrompe il presupposto che hai erroneamente fatto anche se era basato solo sull'attuale implementazione, non sui documenti). Penso che questo sia un comportamento piuttosto brutto e un consiglio piuttosto brutto.
Palec,

17
@Palec: "Normalmente non è necessario sottoclassare l'Applicazione." - Questo è solo un suggerimento. Uso ancora la funzionalità ufficialmente documentata nel modo previsto. - All'inizio usavo quei "singoletti statici" e si sono rivelati un dolore nell'inizializzazione pigra ... ha i suoi problemi. Soprattutto se utilizzato con test di strumentazione. - Ho ancora quei Singleton per la modularità, ma li ho istanziati in blocco nella onCreate di una sottoclasse android.app.Application. - Funziona come un fascino.
Martin,

9
@Martin avrei dovuto chiarire: la mia reazione riguardava solo la prima frase. "Non ascoltare il documento." Questo è generalmente un consiglio molto pericoloso. Ma "Questo è solo un suggerimento: in questo caso puoi ignorare il documento se hai un motivo e te lo mostrerò ..." mi sembra assolutamente OK.
Palec,

3
"quando si scrive codice in un ricevitore di trasmissione, che non è un contesto ma nel contesto del metodo onReceive viene fornito un contesto, è possibile chiamare getApplicationContext (). Ciò significa anche che NON è garantito l'accesso alla propria applicazione in un BroadcastReceiver. " Quindi cosa possiamo fare per accedere alla mia classe di applicazione in BroadcastReceiver?
Dr.jacky,

30

Confronta getApplication()e getApplicationContext().

getApplicationrestituisce un Applicationoggetto che ti consentirà di gestire lo stato globale dell'applicazione e rispondere ad alcune situazioni del dispositivo come onLowMemory()e onConfigurationChanged().

getApplicationContextrestituisce il contesto dell'applicazione globale - la differenza rispetto ad altri contesti è che, ad esempio, un contesto di attività potrebbe essere distrutto (o reso altrimenti non disponibile) da Android al termine dell'attività. Il contesto dell'applicazione rimane disponibile per tutto il tempo in cui esiste l'oggetto applicazione (che non è legato a uno specifico Activity), quindi è possibile utilizzarlo per cose come le notifiche che richiedono un contesto che sarà disponibile per periodi più lunghi e indipendente dagli oggetti IU transitori.

Immagino che dipenda da cosa sta facendo il tuo codice se questi possono o meno essere gli stessi - anche se in uso normale, mi aspetto che siano diversi.


19
ma an Application is a Context(eredita da esso) e in fase di esecuzione entrambi i metodi restituiscono la stessa istanza. Quindi qual è la differenza?
Matthias,

3
La differenza è l'ambito. Il contesto della tua applicazione sarà valido molto più a lungo di, per esempio, un contesto di attività perché l'attività potrebbe essere in uso solo per un tempo molto breve, mentre la tua applicazione potrebbe essere composta da molte attività. Il tuo contesto di attività sarà valido almeno fino a quando la durata inizia quando inizia la prima attività e termina quando l'ultima attività. Sono tutti contesti, ma uno è più duraturo e non cambia, ma altri sono di breve durata e istanze diverse possono avere contesti diversi.
RivieraKid,

16
Penso che potresti aver letto male la mia domanda. Non sto chiedendo la differenza tra un Activitycontesto e un Applicationcontesto. Sto riflettendo sulla differenza tra Application(che è il contesto unico e globale dell'applicazione) e qualunque cosa getApplicationContextritorni. Quest'ultimo infatti non funzionava prima di Android 1.6; tornava sempre null.
Matthias,

1
@Matthias Secondo me è ancora rilevante. Il contesto viene iniettato (implementato) dal sistema Android stesso, mentre l'applicazione eredita ed estende il contesto. La classe di applicazione può essere facilmente derisa (come detto da te), quindi non è una scommessa sicura che mostra che la classe di applicazione fa un po 'di "magia" (nel progetto di test) per raggiungerlo, forse ignorando il contesto iniettato?
Audrius,

3
Vieni di nuovo? Mi dispiace, ancora non vedo come questo risponda alla mia domanda.
Matthias,

30

Sembra avere a che fare con il contesto. La maggior parte delle classi derivate Contextsono in realtà a ContextWrapper, che essenzialmente delega in un altro contesto, possibilmente con modifiche da parte del wrapper.

Il contesto è un'astrazione generale che supporta derisione e proxy. Poiché molti contesti sono legati a un oggetto a durata limitata come un Activity, ci deve essere un modo per ottenere un contesto di maggiore durata, per scopi come la registrazione per le notifiche future. Ciò è ottenuto da Context.getApplicationContext(). Un'implementazione logica consiste nel restituire l' Applicationoggetto globale , ma nulla impedisce a un'implementazione di contesto di restituire un wrapper o un proxy con una durata adeguata.

Attività e servizi sono associati in modo più specifico a un Applicationoggetto. L'utilità di questo, credo, è che puoi creare e registrare nel manifest una classe personalizzata derivata Applicationed essere certo che Activity.getApplication()o Service.getApplication()restituirà quell'oggetto specifico di quel tipo specifico, che puoi trasmettere alla tua Applicationclasse derivata e usare per qualunque cosa scopo personalizzato.

In altre parole, getApplication()è garantito per restituire un Applicationoggetto, mentre getApplicationContext()è libero di restituire un proxy.


Quando dici "il contesto è un'astrazione generale che supporta beffardo e proxy" cosa intendi per "proxy" esattamente? Potresti indicarmi alcuni riferimenti? Trovo l'intera cosa del Contesto abbastanza contorta.
Tiago,

@Tiago Questa risposta può aiutarti a capire meglio: stackoverflow.com/questions/10641144/…
superutente

-13

Per rispondere alla domanda, getApplication () restituisce un oggetto Application e getApplicationContext () restituisce un oggetto Context. Sulla base delle tue osservazioni, presumo che il contesto di entrambi sia identico (ovvero dietro le quinte la classe Application chiama quest'ultima funzione per popolare la parte Context della classe base o si verifica un'azione equivalente). Non dovrebbe importare davvero quale funzione chiami se hai solo bisogno di un contesto.

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.