getApplication () vs. getApplicationContext ()

417

Não consegui encontrar uma resposta satisfatória para isso, então vamos lá: qual é o problema Activity/Service.getApplication()e Context.getApplicationContext()?

Em nossa aplicação, ambos retornam o mesmo objeto. No ActivityTestCaseentanto, a zombaria do aplicativo getApplication()retornará com a zombaria, mas getApplicationContextainda retornará uma instância de contexto diferente (uma injetada pelo Android). Isso é um bug? É de propósito?

Eu nem entendo a diferença em primeiro lugar. Existem casos fora de um conjunto de testes em que ambas as chamadas podem retornar com objetos diferentes? Quando e porque? Além disso, por que é getApplicationdefinido em Activitye Service, mas não em Context? Não deve sempre haver uma instância de aplicativo válida disponível em qualquer lugar ?

Matthias
fonte
8
Boa pergunta. O material de teste é um pouco misterioso (como você bem sabe). Mas eu me pergunto se alguma diferença se manifesta nessas duas chamadas de método se você não criar explicitamente um Applicationobjeto no seu aplicativo.
Christopher Orr

Respostas:

366

Pergunta muito interessante. Eu acho que é principalmente um significado semântico, e também pode ser devido a razões históricas.

Embora nas implementações atuais da Atividade e Serviço do Android getApplication()e getApplicationContext()retornem o mesmo objeto, não há garantia de que sempre será esse o caso (por exemplo, em uma implementação específica do fornecedor).

Portanto, se você deseja a classe Application registrada no Manifest, nunca deve chamá-la getApplicationContext()e transmiti-la ao seu aplicativo, pois pode não ser a instância do aplicativo (que você obviamente experimentou com a estrutura de teste).

Por que getApplicationContext()existe em primeiro lugar?

getApplication()está disponível apenas na classe Activity e Service, enquanto que getApplicationContext()é declarado na classe Context.

Na verdade, isso significa uma coisa: ao escrever código em um receptor de transmissão, que não é um contexto, mas recebe um contexto em seu método onReceive, você pode chamar apenas getApplicationContext(). O que também significa que você não tem garantia de ter acesso ao seu aplicativo em um BroadcastReceiver.

Ao analisar o código do Android, você vê que, quando anexada, uma atividade recebe um contexto base e um aplicativo, e esses são parâmetros diferentes. getApplicationContext()delega sua chamada baseContext.getApplicationContext().

Mais uma coisa: a documentação diz que, na maioria dos casos, você não precisa subclassificar Application:

Normalmente, não há necessidade de subclasse Application. Na maioria das situações, singletons estáticos podem fornecer a mesma funcionalidade de uma maneira mais modular. Se o seu singleton precisar de um contexto global (por exemplo, para registrar receptores de transmissão), a função para recuperá-lo poderá receber uma Contextque seja usada internamente Context.getApplicationContext()ao construir o singleton pela primeira vez.

Eu sei que essa não é uma resposta exata e precisa, mas ainda assim, isso responde à sua pergunta?

Pierre-Yves Ricau
fonte
89
@ Piwaï: Não dê ouvidos ao documento. Subclassificação android.app.Applicationé super ajuda completa. Por exemplo, tive problemas sem fim ao inicializar o banco de dados. Uma vez que se mudou para Application.onCreateele funcionou como um encanto. Agora eu faço toda a inicialização de todo o sistema Applicatione não escreveria outro aplicativo sem.
Martin
9
@Martin Não ouvir os documentos geralmente significa que seu código pode quebrar no futuro, ou mesmo agora em condições inesperadas, perder portabilidade, ter um desempenho ruim, impedir que os desenvolvedores da plataforma façam uma alteração benéfica (que quebra a suposição que você fez incorretamente, embora tenha sido com base apenas na implementação atual, não nos documentos). Eu acho que isso é um comportamento muito ruim e um conselho muito ruim.
Palec 5/02/2014
17
@Palec: “Normalmente não há necessidade de subclassificar Application.” - Isso é apenas uma dica. Eu ainda uso a funcionalidade oficialmente documentada da maneira pretendida. - Eu costumava usar esses “singletons estáticos” no começo e eles acabaram sendo uma dor na… - a inicialização preguiçosa tem seus problemas. Especialmente quando usado com testes de instrumentação. - Ainda tenho esses Singletons para modularidade, mas os instanciamos em bloco no onCreate de uma subclasse android.app.Application. - Funciona como um encanto.
Martin Martin
9
@ Martin, eu deveria ter deixado claro: minha reação dizia respeito apenas à primeira frase. "Não dê ouvidos ao documento." Isso geralmente é um conselho muito perigoso. Mas "Esta é apenas uma dica - você pode ignorar o documento nesse caso, se tiver um motivo e eu vou lhe mostrar uma ..." parece absolutamente bom para mim.
Palec 06/02
3
"ao escrever código em um receptor de broadcast, que não é um contexto, mas recebe um contexto em seu método onReceive, você pode chamar apenas getApplicationContext (). O que também significa que NÃO é garantido que você tenha acesso ao seu aplicativo em um BroadcastReceiver. " .Então, o que podemos fazer para acessar minha classe de aplicativo no BroadcastReceiver?
Dr.jacky
30

Compare getApplication()e getApplicationContext().

getApplicationretorna um Applicationobjeto que permitirá que você gerencie seu estado global de aplicativo e responda a algumas situações do dispositivo como onLowMemory()e onConfigurationChanged().

getApplicationContextretorna o contexto global do aplicativo - a diferença de outros contextos é que, por exemplo, um contexto de atividade pode ser destruído (ou tornar indisponível) pelo Android quando a atividade terminar. O contexto do aplicativo permanece disponível o tempo todo, enquanto o objeto Aplicativo existe (que não está vinculado a um específico Activity), para que você possa usá-lo em itens como Notificações que exigem um contexto que estará disponível por períodos mais longos e independente dos objetos de interface de usuário transitórios.

Eu acho que depende do que o seu código está fazendo, se estes podem ou não ser os mesmos - embora em uso normal, eu esperaria que eles fossem diferentes.

RivieraKid
fonte
19
mas an Application é um Context(herdado dele) e, em tempo de execução, os dois métodos retornam a mesma instância. Então qual a diferença?
Matthias
3
A diferença é o escopo. O contexto do seu Aplicativo será válido por muito mais tempo do que, digamos, um contexto de Atividade, porque a atividade pode ser usada apenas por um período muito curto, enquanto o seu Aplicativo pode consistir em muitas Atividades. O seu Contexto de atividade será válido pelo menos enquanto a duração começar quando a primeira atividade for iniciada e terminar quando a última atividade. Todos eles são contextos, mas um é mais duradouro e não muda, mas outros são de curta duração, e diferentes instâncias podem ter contextos diferentes.
RivieraKid
16
Eu acho que você pode estar interpretando mal a minha pergunta. Não estou pedindo a diferença entre um Activitycontexto e um Applicationcontexto. Estou refletindo sobre a diferença entre Application(que é o contexto de aplicativo exclusivo e global) e o que quer que getApplicationContextretorne. O último não era funcional antes do Android 1.6; costumava sempre voltar null.
Matthias
1
@ Matthias Na minha opinião, ainda é relevante. O contexto é injetado (implementado) pelo próprio sistema Android, enquanto o Aplicativo herda e estende o Contexto. A classe de aplicativo pode ser facilmente zombada (como você disse); então, não é uma aposta segura que mostre que a classe de aplicativo faz alguma "mágica" (no projeto de teste) para alcançá-la, possivelmente ignorando o contexto injetado?
Audrius
3
Volte novamente? Sinto muito, ainda não vejo como isso responde à minha pergunta.
Matthias
30

Parece ter a ver com quebra de contexto. A maioria das classes derivadas Contexté na verdade a ContextWrapper, que essencialmente delega para outro contexto, possivelmente com alterações pelo wrapper.

O contexto é uma abstração geral que suporta zombaria e proxy. Como muitos contextos estão vinculados a um objeto de duração limitada, como um Activity, é preciso haver uma maneira de obter um contexto de vida mais longa, para fins como o registro para notificações futuras. Isso é alcançado por Context.getApplicationContext(). Uma implementação lógica é retornar o Applicationobjeto global , mas nada impede que uma implementação de contexto retorne um wrapper ou proxy com uma vida útil adequada.

Atividades e serviços estão mais especificamente associados a um Applicationobjeto. A utilidade desta, creio eu, é que você pode criar e registrar no manifesto uma classe personalizada derivada Applicatione ter a certeza de que Activity.getApplication()ou Service.getApplication()vai retornar esse objeto específico desse tipo específico, que você pode transmitir para o derivado Applicationclasse e uso por qualquer finalidade personalizada.

Em outras palavras, getApplication()é garantido retornar um Applicationobjeto, enquanto getApplicationContext()é livre para retornar um proxy.

usethe4ce
fonte
Quando você diz "o contexto é uma abstração geral que suporta zombaria e proxy", o que você quer dizer com "proxy" exatamente? Você poderia me indicar algumas referências? Acho a coisa toda do Contexto bastante complicada.
Tiago
@Tiago Esta resposta pode ajudá-lo a entender melhor: stackoverflow.com/questions/10641144/…
superuser
-13

Para responder à pergunta, getApplication () retorna um objeto Application e getApplicationContext () retorna um objeto Context. Com base em suas próprias observações, eu suporia que o contexto de ambos é idêntico (ou seja, nos bastidores, a classe Application chama a última função para preencher a parte de contexto da classe base ou ocorre alguma ação equivalente). Realmente não importa qual função você chama se você apenas precisar de um Contexto.

Lenny Porter
fonte