getApplication () vs. getApplicationContext ()

417

Nie mogłem znaleźć satysfakcjonującej odpowiedzi na to pytanie, więc zaczynamy: o co chodzi z tym Activity/Service.getApplication()i Context.getApplicationContext()?

W naszej aplikacji oba zwracają ten sam obiekt. W ActivityTestCaseJednakże, szydząc aplikację pozwoli getApplication()wrócić z makiety, ale getApplicationContextbędzie jeszcze powrócić inną instancję kontekstowe (jeden wstrzykiwany przez Android). Czy to błąd? Czy to celowo?

W ogóle nie rozumiem różnicy. Czy istnieją przypadki poza zestawem testowym, w których oba połączenia mogą wracać z różnymi obiektami? Kiedy i dlaczego Ponadto, dlaczego jest getApplicationzdefiniowana na Activitya Service, ale nie na Context? Czy nie zawsze powinna być dostępna poprawna instancja aplikacji z dowolnego miejsca ?

Matthias
źródło
8
Dobre pytanie. Testowanie jest tajemnicą (jak dobrze wiesz). Ale zastanawiam się, czy jakakolwiek różnica przejawia się w tych dwóch wywołaniach metod, jeśli nie utworzysz bezpośrednio Applicationobiektu w swojej aplikacji.
Christopher Orr

Odpowiedzi:

366

Bardzo interesujące pytanie. Myślę, że ma to głównie znaczenie semantyczne i może być również spowodowane względami historycznymi.

Chociaż w bieżących implementacjach Android Activity i Service getApplication()i getApplicationContext()zwracających ten sam obiekt, nie ma gwarancji, że zawsze tak będzie (na przykład w przypadku konkretnej implementacji dostawcy).

Jeśli więc chcesz mieć klasę aplikacji zarejestrowaną w Manifeście, nigdy nie powinieneś wywoływać jej getApplicationContext()i przesyłać do aplikacji, ponieważ może to nie być instancja aplikacji (czego oczywiście doświadczyłeś w środowisku testowym).

Dlaczego w ogóle getApplicationContext()istnieje?

getApplication()jest dostępna tylko w klasie Activity i Service, podczas gdy getApplicationContext()jest zadeklarowana w klasie Context.

To w rzeczywistości oznacza jedną rzecz: pisząc kod w odbiorniku rozgłoszeniowym, który nie jest kontekstem, ale otrzymuje kontekst w metodzie onReceive, możesz tylko wywoływać getApplicationContext(). Co oznacza również, że nie masz gwarancji dostępu do aplikacji w BroadcastReceiver.

Patrząc na kod Androida, widzisz, że po dołączeniu aktywność otrzymuje podstawowy kontekst i aplikację, a są to różne parametry. getApplicationContext()przekazuje połączenie baseContext.getApplicationContext().

Jeszcze jedna rzecz: dokumentacja mówi, że w większości przypadków nie trzeba podklasować aplikacji:

Zwykle nie ma potrzeby podziału na klasy Application. W większości sytuacji statyczne singletony mogą zapewnić tę samą funkcjonalność w bardziej modułowy sposób. Jeśli twój singleton potrzebuje globalnego kontekstu (na przykład, aby zarejestrować odbiorniki rozgłoszeniowe), można odzyskać funkcję, Contextktóra będzie używana wewnętrznie Context.getApplicationContext()podczas pierwszej budowy singletonu.

Wiem, że to nie jest dokładna i precyzyjna odpowiedź, ale czy to odpowiada na twoje pytanie?

Pierre-Yves Ricau
źródło
89
@ Piwaï: Nie słuchaj dokumentu. Podklasowanie android.app.Applicationto pełna pomoc. Na przykład miałem niekończące się problemy z inicjowaniem bazy danych. Po przeniesieniu Application.onCreatedziałało jak urok. Teraz wykonuję całą inicjalizację całego systemu Applicationi nie napisałbym bez niej innej aplikacji.
Martin
9
@Martin Nie słuchanie dokumentów ogólnie oznacza, że ​​Twój kod może ulec uszkodzeniu w przyszłości, a nawet teraz w nieoczekiwanych warunkach, utracić przenośność, działać źle, uniemożliwić programistom platform dokonanie korzystnej zmiany (to łamie założenie, które błędnie przyjęłeś, chociaż było na podstawie tylko bieżącej implementacji, a nie dokumentów). Myślę, że jest to dość złe zachowanie i dość zła rada.
Palec
17
@Palec: „Zwykle nie ma potrzeby podklasy aplikacji”. - To tylko wskazówka. Nadal korzystam z oficjalnie udokumentowanej funkcjonalności w zamierzony sposób. - Kiedyś używałem tych „statycznych singletonów” na początku i okazały się one bolesne w… - leniwa inicjalizacja ma swoje problemy. Zwłaszcza w połączeniu z testami oprzyrządowania. - Wciąż mam te Singletony ze względu na modułowość, ale tworzę je w bloku onCreate podklasy android.app.Application. - działa jak marzenie.
Martin
9
@Martin Powinienem był jasno powiedzieć: moja reakcja dotyczyła tylko pierwszego zdania. „Nie słuchaj doktora”. Jest to ogólnie bardzo niebezpieczna rada. Ale „To tylko wskazówka - w tym przypadku możesz zignorować dokument, jeśli masz powód, a ja ci go pokażę…” brzmi dla mnie absolutnie OK.
Palec
3
„podczas pisania kodu w odbiorniku rozgłoszeniowym, który nie jest kontekstem, ale otrzymuje metodę w ramach metody onReceive, można wywołać tylko funkcję getApplicationContext (). Oznacza to również, że NIE gwarantuje się dostępu do aplikacji w BroadcastReceiver. „ .Co więc możemy zrobić, aby uzyskać dostęp do mojej klasy aplikacji w BroadcastReceiver?
Dr.jacky
30

Porównaj getApplication()i getApplicationContext().

getApplicationzwraca Applicationobiekt, który pozwoli ci zarządzać globalnym stanem aplikacji i reagować na niektóre sytuacje urządzenia, takie jak onLowMemory()i onConfigurationChanged().

getApplicationContextzwraca globalny kontekst aplikacji - różnica w porównaniu z innymi kontekstami polega na tym, że na przykład kontekst działania może zostać zniszczony (lub w inny sposób niedostępny) przez system Android po zakończeniu działania. Kontekst aplikacji pozostaje dostępny przez cały czas istnienia obiektu aplikacji (który nie jest powiązany z konkretnym Activity), dzięki czemu można go używać do takich rzeczy, jak Powiadomienia, które wymagają kontekstu, który będzie dostępny przez dłuższy czas i niezależny od przejściowych obiektów interfejsu użytkownika.

Wydaje mi się, że zależy to od tego, co robi Twój kod, czy mogą one być takie same, ale nie w normalnym użyciu, ale oczekiwałbym, że będą inne.

RivieraKid
źródło
19
ale Application jestContext (dziedziczy z niego), a w czasie działania, obie metody zwrócić ten sam przypadek. Jaka jest różnica?
Matthias
3
Różnica polega na zakresie. Kontekst aplikacji będzie ważny znacznie dłużej niż, powiedzmy, kontekst działania, ponieważ działanie może być używane tylko przez bardzo krótki czas, podczas gdy aplikacja może składać się z wielu działań. Twój kontekst działania będzie ważny przynajmniej przez czas trwania, który rozpoczyna się w momencie rozpoczęcia pierwszego działania i kończy w momencie ostatniego działania. Wszystkie są Kontekstami, ale jeden trwa dłużej i się nie zmienia, ale inne są krótkotrwałe, a różne instancje mogą mieć różne Konteksty.
RivieraKid
16
Myślę, że źle rozumiesz moje pytanie. Nie pytam o różnicę między Activitykontekstem a Applicationkontekstem. Zastanawiam się nad różnicą między Application(który jest globalnym, unikalnym kontekstem aplikacji) a tym, co getApplicationContextzwraca. Ten ostatni w rzeczywistości nie działał przed Androidem 1.6; zawsze wracało null.
Matthias
1
@Matthias Moim zdaniem jest to nadal aktualne. Kontekst jest wstrzykiwany (wdrażany) przez sam system Android, natomiast aplikacja dziedziczy i rozszerza kontekst. Klasa aplikacji może być łatwo wyśmiewana (jak powiedziałeś), to czy nie jest to bezpieczny zakład, że pokazuje, że klasa aplikacji wykonuje jakąś „magię” (w projekcie testowym), aby ją osiągnąć, być może ignorując wstrzyknięty kontekst?
Audrius
3
Wracać? Przepraszam, wciąż nie rozumiem, jak to odpowiada na moje pytanie.
Matthias
30

Wydaje się, że ma to związek z zawijaniem kontekstu. Większość klas pochodnych Contextto tak naprawdę ContextWrapper, co zasadniczo deleguje do innego kontekstu, prawdopodobnie ze zmianami opakowania.

Kontekst jest ogólną abstrakcją, która wspiera drwiny i proxy. Ponieważ wiele kontekstów jest powiązanych z obiektem o ograniczonym czasie życia, takim jak an Activity, musi istnieć sposób na uzyskanie dłuższego kontekstu, na przykład w celu rejestracji w celu otrzymywania powiadomień w przyszłości. Osiąga się to przez Context.getApplicationContext(). Logiczną implementacją jest zwrócenie Applicationobiektu globalnego , ale nic nie stoi na przeszkodzie, aby implementacja kontekstu zwróciła opakowanie lub serwer proxy z odpowiednim czasem życia.

Działania i usługi są bardziej konkretnie powiązane z Applicationobiektem. Uważam, że użyteczność tego polega na tym, że możesz utworzyć i zarejestrować w manifeście niestandardową klasę pochodzącą z Applicationi mieć pewność, że Activity.getApplication()lub Service.getApplication()zwróci ten konkretny obiekt tego określonego typu, który możesz rzucić na Applicationklasę pochodną i używać do czegokolwiek cel niestandardowy.

Innymi słowy, getApplication()gwarantowane jest zwrócenie Applicationobiektu, podczas gdy getApplicationContext()zamiast tego można zwrócić proxy.

usethe4ce
źródło
Kiedy mówisz „kontekst jest ogólną abstrakcją, która wspiera drwiny i przybliżanie”, co dokładnie rozumiesz przez „przybliżanie”? Czy możesz wskazać mi jakieś odniesienia? Uważam, że cały kontekst jest dość skomplikowany.
Tiago,
@Tiago Ta odpowiedź może pomóc Ci lepiej zrozumieć: stackoverflow.com/questions/10641144/…
superuser
-13

Aby odpowiedzieć na pytanie, getApplication () zwraca obiekt Application, a getApplicationContext () zwraca obiekt Context. Opierając się na twoich własnych spostrzeżeniach, zakładam, że kontekst obu jest identyczny (tj. Za kulisami klasa aplikacji wywołuje tę drugą funkcję w celu wypełnienia części kontekstu klasy podstawowej lub ma miejsce równoważne działanie). Tak naprawdę nie powinno mieć znaczenia, którą funkcję wywołujesz, jeśli potrzebujesz tylko kontekstu.

Lenny Porter
źródło