getApplication () і getApplicationContext ()


417

Я не міг знайти задовільну відповідь на цей питання , так що тут ми йдемо: то , що угода з Activity/Service.getApplication()і Context.getApplicationContext()?

У нашому додатку обидва повертають один і той же об’єкт. В одному , ActivityTestCaseпроте, глузливий додаток зробить getApplication()повернутися з знущатися, але по- getApplicationContext, як і раніше буде повертати інший контекст примірника (один впорскується Android). Це помилка? Це цілеспрямовано?

Я навіть не розумію різниці в першу чергу. Чи є випадки поза тестовим набором, коли обидва дзвінки можуть повертатися з різними об'єктами? Коли і чому? Крім того, чому getApplicationвизначено на Activityі Service, але не на Context? Чи не завжди має бути дійсний примірник програми, доступний з будь-якого місця ?


8
Приємне запитання. Тестування матеріалів - це таємниця (як ви добре знаєте). Але мені цікаво, чи якась різниця проявляється в цих двох викликах методів, якщо ви явно не створюєте Applicationоб'єкт у вашій програмі.
Крістофер Орр

Відповіді:


366

Дуже цікаве запитання. Я думаю, що це в основному смислове значення, а також може бути пов'язано з історичними причинами.

Незважаючи на те, що в поточних реалізаціях Android Activity і Service getApplication()і getApplicationContext()повертається той самий об’єкт, немає гарантії, що так буде завжди (наприклад, у конкретній реалізації постачальника).

Отже, якщо ви хочете, щоб клас Application, який ви зареєстрували в Manifest, ніколи не повинен дзвонити getApplicationContext()і передавати його своїй програмі, тому що це може бути не екземпляр програми (що, очевидно, ви мали досвід тестових рамок).

Чому getApplicationContext()існує в першу чергу?

getApplication()доступний лише у класі активності та у службовому класі, тоді getApplicationContext()як оголошується у класі контексту.

Це насправді означає одне: коли ви пишете код у широкомовному приймачі, який не є контекстом, а надається контекстом у його методі onReceive, ви можете лише зателефонувати getApplicationContext(). Це також означає, що вам не гарантується доступ до вашої програми в BroadcastReceiver.

Переглядаючи код Android, ви бачите, що при вкладенні активність отримує базовий контекст і додаток, і це різні параметри. getApplicationContext()делегатів, на які він закликає baseContext.getApplicationContext().

І ще одне: документація говорить про те, що в більшості випадків вам не потрібно підкласифікувати додаток:

Зазвичай не потрібно підклас Application. У більшості випадків статичні одинаки можуть надавати однакові функціональні можливості більш модульним способом. Якщо вашому синглтону потрібен глобальний контекст (наприклад, для реєстрації приймачів широкомовної передачі), функція його отримання може бути надана функцією, Contextяка використовується внутрішньо Context.getApplicationContext()при першому конструюванні сингтона.

Я знаю, що це не точна і точна відповідь, але все-таки це відповідає на ваше запитання?


89
@ Piwaï: Не слухайте документа. Підкласифікація android.app.Application- це супер допомога. Наприклад, у мене були нескінченні проблеми при ініціалізації бази даних. Одного разу переїхавши до Application.onCreateнього, працював як шарм. Зараз я роблю всю ініціалізацію системи, Applicationі я б не писав іншого додатка без цього.
Мартін

9
@Martin Якщо ви не слухаєте документи, це означає, що ваш код може в майбутньому зламатися або навіть зараз у несподіваних умовах втратити портативність, погано працювати, заважати розробникам платформи вносити корисні зміни (що порушує припущення, яке ви зробили неправильно, хоча це було заснована тільки на поточній реалізації, а не на документах). Я думаю, що це досить погана поведінка та досить погана порада.
Палець

17
@Palec: "Зазвичай додаток підкласу не потрібно." - Це просто натяк. Я все ще використовую офіційно задокументовану функціональність за призначенням. - Раніше я використовував ті "статичні одинаки", і вони виявились болями в ... - лінива ініціалізація має свої проблеми. Особливо при використанні приладів тестів. - У мене все ще є ті Singletons для модульності, але я інстанціюю їх в блоці в onCreate підкласу android.app.Application. - працює як шарм.
Мартін

9
@Martin Я повинен був дати зрозуміти: моя реакція стосувалася лише першого речення. "Не слухайте документа". Це взагалі дуже небезпечна порада. Але "Це лише натяк - ви можете проігнорувати документ у цьому випадку, якщо у вас є причина, і я покажу вам ..." для мене звучить абсолютно нормально.
Палець

3
"Коли ви записуєте код у широкомовному приймачі, який не є контекстом, але йому надається контекст у його методі onReceive, ви можете зателефонувати лише getApplicationContext (). Це також означає, що вам НЕ гарантовано мати доступ до вашої програми в BroadcastReceiver. " .Так що ми можемо зробити для доступу до мого класу додатків у BroadcastReceiver?
Dr.jacky

30

Порівняйте getApplication()і getApplicationContext().

getApplicationповертає Applicationоб’єкт, який дозволить вам керувати своїм глобальним станом програми та реагувати на деякі ситуації на пристрої, такі як onLowMemory()і onConfigurationChanged().

getApplicationContextповертає глобальний контекст програми - відмінність від інших контекстів полягає в тому, що, наприклад, Android може бути знищений (або іншим чином недоступний) Android, коли ваша діяльність закінчиться. Контекст програми залишається доступним весь час, поки існує ваш об’єкт Application (який не прив'язаний до конкретного Activity), тому ви можете використовувати це для речей, як сповіщення, для яких потрібен контекст, який буде доступний протягом більш тривалого періоду та незалежно від перехідних об'єктів інтерфейсу.

Я думаю, це залежить від того, що робить ваш код, чи вони можуть бути, чи не можуть бути однаковими, хоча я б при звичайному використанні очікував, що вони будуть різними.


19
але an Application - це Context(він успадковує його), і під час виконання обох методів повертається один і той же екземпляр. То яка різниця?
Маттіас

3
Різниця - сфера застосування. Контекст вашої програми буде дійсним набагато довше, ніж, скажімо, контекст діяльності, оскільки ця діяльність може використовуватися лише дуже короткий час, тоді як ваша заявка може складатися з багатьох заходів. Контекст вашої активності буде дійсним щонайменше до тих пір, поки триває тривалість, яка починається з початку першої діяльності та закінчується, коли остання активність. Всі вони є контекстами, але один є більш тривалим і не змінюється, а інші є короткочасними, і різні випадки можуть мати різні контексти.
RivieraKid

16
Я думаю, ви можете неправильно читати моє запитання. Я не прошу різниці між Activityконтекстом і Applicationконтекстом. Я розмірковую над різницею Application(що є глобальним, унікальним контекстом програми) і тим, що getApplicationContextповертається. Останній насправді був нефункціональним перед Android 1.6; вона завжди поверталася null.
Маттіас

1
@Matthias На мою думку, це все ще актуально. Контекст вводиться (реалізується) самою системою Android, тоді як Application успадковує та розширює Context. Клас програми можна легко знущатись (як ви сказали), то хіба це не безпечна ставка, що це показує, що клас Application робить якусь "магію" (в тестовому проекті) для досягнення цього, можливо, ігноруючи введений контекст?
Адріус

3
Завітайте знову? Вибачте, я досі не бачу, як це відповідає на моє запитання.
Маттіас

30

Здається, це стосується обговорення контексту. Більшість класів, похідних від Contextнасправді, є a ContextWrapper, який по суті делегує іншому контексту, можливо, із змінами, яку обгортає.

Контекст - це загальна абстракція, яка підтримує глузування та наближення. Оскільки багато контекстів пов'язані з об'єктом з обмеженим терміном експлуатації, таким як, наприклад, an Activity, існує необхідний спосіб отримати контекст з тривалістю життя для таких цілей, як реєстрація для майбутніх сповіщень. Це досягається шляхом Context.getApplicationContext(). Логічна реалізація полягає у поверненні глобального Applicationоб'єкта, але ніщо не перешкоджає реалізації контексту повернення обгортки або проксі-сервера з відповідним терміном експлуатації.

Діяльність та послуги більш конкретно пов'язані з Applicationоб’єктом. Корисність цього, я вважаю, полягає в тому, що ви можете створити і зареєструвати в маніфесті користувацький клас, похідний від Applicationі бути впевненим, що Activity.getApplication()або Service.getApplication()поверне той конкретний об'єкт того конкретного типу, який ви можете передавати вашому похідному Applicationкласу і використовувати для будь-якого спеціальна мета.

Іншими словами, getApplication()гарантовано повернути Applicationоб’єкт, тоді getApplicationContext()як вільний повернути проксі натомість.


Коли ви говорите "контекст - це загальна абстракція, яка підтримує глузування та наближення", що ви маєте на увазі під "наближенням" саме? Не могли б ви вказати мені на деякі посилання? Я вважаю всю річ Контексту досить зведеною.
Тіаго

@Tiago Ця відповідь допоможе вам зрозуміти краще: stackoverflow.com/questions/10641144/…
суперрусер

-13

Щоб відповісти на питання, getApplication () повертає об’єкт Application, а getApplicationContext () повертає об'єкт Context. Виходячи з ваших власних спостережень, я вважаю, що контекст обох є однаковим (тобто поза кадром клас Application викликає останню функцію для заповнення частини контексту базового класу або відбувається якесь еквівалентне дію). Насправді не має значення, яку функцію ви викликаєте, якщо вам просто потрібен контекст.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.