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()доступно только в классе Activity и классе Service, тогда getApplicationContext()как объявлено в классе Context.

На самом деле это означает одно: при написании кода в широковещательном приемнике, который не является контекстом, а задан контекст в его методе onReceive, вы можете только вызывать getApplicationContext(). Это также означает, что вам не гарантирован доступ к вашему приложению в BroadcastReceiver.

Глядя на код Android, вы видите, что при подключении активность получает базовый контекст и приложение, и это разные параметры. getApplicationContext()делегаты это вызов baseContext.getApplicationContext().

Еще одна вещь: в документации сказано, что в большинстве случаев вам не нужно создавать подкласс Application:

Обычно нет необходимости создавать подклассы Application. В большинстве случаев статические синглтоны могут предоставлять ту же функциональность более модульным способом. Если вашему синглтону необходим глобальный контекст (например, для регистрации широковещательных приемников), функции для его извлечения может быть предоставлена ​​функция, Contextкоторая используется внутри Context.getApplicationContext()при первом создании синглтона.

Я знаю, что это не точный и точный ответ, но все же, это отвечает на ваш вопрос?

Пьер-Ив Рикау
источник
89
@ Piwaï: не слушай док. Подклассы android.app.Applicationэто супер помощь полный. Например, у меня были бесконечные проблемы с инициализацией базы данных. Когда-то переехал в Application.onCreateнего работал как шарм. Теперь я делаю всю системную инициализацию в, Applicationи я не написал бы другое приложение без.
Мартин
9
@ Мартин Не слушая документы, как правило, означает, что ваш код может сломаться в будущем, или даже сейчас, в неожиданных условиях, потерять переносимость, работать плохо, помешать разработчикам платформы внести полезные изменения (что нарушает предположение, которое вы ошибочно сделали, хотя это было основываясь только на текущей реализации, а не на документах). Я думаю, что это довольно плохое поведение и довольно плохой совет.
Palec
17
@Palec: «Обычно нет необходимости создавать подкласс Application». - Это всего лишь подсказка. Я все еще использую официально документированную функциональность по назначению. - Я использовал эти «статические синглеты» вначале, и они оказались болью в… - У ленивой инициализации есть свои проблемы. Особенно при использовании с контрольно-измерительными приборами. - У меня все еще есть эти Singletons для модульности, но я создаю их экземпляр в блоке в onCreate подкласса android.app.Application. - работает как шарм.
Мартин
9
@ Мартин Я должен был дать понять: моя реакция касалась только первого предложения. «Не слушай док.» Это вообще очень опасный совет. Но «Это просто подсказка - в этом случае вы можете игнорировать документ, если у вас есть причина, и я вам ее покажу…», звучит для меня абсолютно нормально.
Palec
3
«при написании кода в широковещательном приемнике, который не является контекстом, а задан контекст в его методе onReceive, вы можете вызвать только getApplicationContext (). Это также означает, что вам НЕ гарантирован доступ к вашему приложению в BroadcastReceiver. " .Так что мы можем сделать, чтобы получить доступ к моему классу приложения в BroadcastReceiver?
Dr.jacky
30

Сравните getApplication()и getApplicationContext().

getApplicationвозвращает Applicationобъект, который позволит вам управлять вашим глобальным состоянием приложения и реагировать на некоторые ситуации устройства, такие как onLowMemory()и onConfigurationChanged().

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

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

RivieraKid
источник
19
но Application этоContext (он наследует от него), а также во время выполнения, оба метода возвращают тот же экземпляр. Так в чем же разница?
Матиас
3
Разница заключается в объеме. Контекст вашего приложения будет действителен гораздо дольше, чем, скажем, контекст действия, потому что действие может использоваться только в течение очень короткого времени, в то время как ваше приложение может состоять из множества действий. Контекст вашей активности будет действителен, по крайней мере, до тех пор, пока он начинается, когда начинается первое действие, и заканчивается, когда последнее действие. Все они являются контекстами, но один длится дольше и не меняется, но другие недолговечны, и разные экземпляры могут иметь разные контексты.
RivieraKid
16
Я думаю, что вы, возможно, неправильно поняли мой вопрос. Я не спрашиваю о разнице между Activityконтекстом и Applicationконтекстом. Я размышляю о разнице между Application(который является глобальным, уникальным контекстом приложения) и тем, что getApplicationContextвозвращается. Последний был фактически неработоспособен до Android 1.6; Раньше всегда возвращался null.
Матиас
1
@Matthias На мой взгляд, это все еще актуально. Контекст внедряется (внедряется) самой системой Android, а Приложение наследует и расширяет Контекст. Класс приложения может быть легко смоделирован (как вы сказали), тогда разве не безопасно, что он показывает, что класс Application делает что-то «волшебное» (в тестовом проекте) для его достижения, возможно, игнорируя введенный Context?
Аудрюс
3
Приходи еще? Извините, я до сих пор не понимаю, как это отвечает на мой вопрос.
Матиас
30

Кажется, это связано с переносом контекста. Большинство классов, производных от Contextних, на самом деле являются a ContextWrapper, которые по существу делегируют другому контексту, возможно, с изменениями оболочкой.

Контекст - это общая абстракция, которая поддерживает насмешки и проксирование. Поскольку многие контексты привязаны к объекту с ограниченным сроком службы, например Activity, для поиска более долгоживущего контекста необходим способ, например, регистрация будущих уведомлений. Это достигается Context.getApplicationContext(). Логическая реализация должна возвращать глобальный Applicationобъект, но ничто не мешает контекстной реализации вместо этого возвращать оболочку или прокси с подходящим временем жизни.

Деятельность и услуги более конкретно связаны с Applicationобъектом. Я полагаю, что полезность этого заключается в том, что вы можете создать и зарегистрировать в манифесте собственный класс, производный от него, Applicationи быть уверенным, что он Activity.getApplication()или Service.getApplication()будет возвращать этот конкретный объект этого конкретного типа, который вы можете привести к производному Applicationклассу и использовать для любых целей. пользовательское назначение.

Другими словами, getApplication()гарантированно вернуть Applicationобъект, в то время getApplicationContext()как свободен для возврата прокси.

usethe4ce
источник
Когда вы говорите «контекст - это общая абстракция, которая поддерживает насмешки и проксирование», что вы подразумеваете под «проксированием»? Не могли бы вы указать мне некоторые ссылки? Я нахожу весь контекст очень запутанным.
Тиаго
@Tiago Этот ответ поможет вам лучше понять: stackoverflow.com/questions/10641144/…
superuser
-13

Чтобы ответить на вопрос, getApplication () возвращает объект Application, а getApplicationContext () возвращает объект Context. Основываясь на ваших собственных наблюдениях, я бы предположил, что оба контекста идентичны (т.е. за кулисами класс Application вызывает последнюю функцию для заполнения части контекста базового класса или происходит какое-то эквивалентное действие). На самом деле не должно иметь значения, какую функцию вы вызываете, если вам нужен контекст.

Ленни Портер
источник