Когда вызывать контекст активности ИЛИ контекст приложения? - PullRequest
252 голосов
/ 04 сентября 2011

Было много сообщений о том, что представляют собой эти два контекста .. Но я все еще не совсем понял

Насколько я понимаю, пока: Каждый является экземпляром своего класса, что означает, что некоторые программисты рекомендуют вам использовать this.getApplicationContext() как можно чаще, чтобы не «вытекать» из памяти. Это связано с тем, что другой this (получающий контекст экземпляра Activity) указывает на Activity, который уничтожается каждый раз, когда пользователь наклоняет телефон или покидает приложение и т. Д. не ловит и поэтому использует слишком много памяти ..

Но может ли кто-нибудь придумать несколько действительно хороших примеров кодирования, где было бы правильно использовать this (получение контекста текущего Activity экземпляра), и контекст приложения будет бесполезным / неправильным?

Ответы [ 7 ]

389 голосов
/ 04 сентября 2011

getApplicationContext() почти всегда неверно. Ms.Хакборн (среди прочих) очень четко сказал, что вы только используете getApplicationContext(), когда знаете , почему вы используете getApplicationContext() и только тогда, когда вам нужно для использования getApplicationContext().

Если говорить прямо, «некоторые программисты» используют getApplicationContext() (или getBaseContext(), в меньшей степени), поскольку их опыт работы с Java ограничен.Они реализуют внутренний класс (например, OnClickListener для Button в Activity) и нуждаются в Context.Вместо того, чтобы использовать MyActivity.this для получения внешнего класса 'this, они используют getApplicationContext() или getBaseContext() для получения Context объекта.

Вы только используйте getApplicationContext() когда вы знаете , вам нужно Context для чего-то, что может прожить дольше, чем любое другое вероятное Context, имеющееся в вашем распоряжении.Сценарии включают:

  • Используйте getApplicationContext(), если вам нужно что-то привязанное к Context, которое само будет иметь глобальную область видимости.Я использую getApplicationContext(), например, в WakefulIntentService, для статического WakeLock, который будет использоваться для службы.Так как это WakeLock является статическим, и мне нужно Context, чтобы получить PowerManager, чтобы создать его, наиболее безопасно использовать getApplicationContext().

  • Использовать getApplicationContext()когда вы связываете Service с Activity, если вы хотите передать ServiceConnection (т. е. дескриптор привязки) между Activity экземплярами через onRetainNonConfigurationInstance().Android внутренне отслеживает привязки через эти ServiceConnections и содержит ссылки на Contexts, которые создают привязки.Если вы выполняете привязку из Activity, то новый экземпляр Activity будет иметь ссылку на ServiceConnection, которая имеет неявную ссылку на старый Activity, а старый Activity не может быть собран мусором.

Некоторые разработчики используют собственные подклассы Application для своих собственных глобальных данных, которые они получают через getApplicationContext().Это конечно возможно.Я предпочитаю статические члены данных, если только по какой-то другой причине вы можете иметь только один пользовательский Application объект.Я создал одно приложение, используя пользовательский объект Application, и обнаружил, что это больно. Ms.Хакборн также согласен с этой позицией .

Вот причины, по которым не использовать getApplicationContext(), куда бы вы ни пошли:

  • Это не такполный Context, поддерживающий все, что Activity делает.Различные вещи, которые вы попробуете сделать с этим Context, потерпят неудачу, в основном связаны с графическим интерфейсом .

  • Это может привести к утечкам памяти, если Contextиз getApplicationContext() удерживает что-то, созданное вашими вызовами, которое вы не можете очистить.С Activity, если он удерживает что-то, как только Activity собирает мусор, все остальное тоже вымывается.Объект Application остается на время жизни вашего процесса.

47 голосов
/ 15 июня 2012

Я думаю, что есть много вещей, которые плохо документированы на сайте SDK, это один из них.Я утверждаю, что мне кажется, что по умолчанию лучше использовать контекст приложения и использовать контекст активности только тогда, когда это действительно необходимо.Единственное место, где я когда-либо видел, что вам нужен контекст активности, - это диалог прогресса.SBERG412 утверждает, что вы должны использовать контекст активности для всплывающего сообщения, однако в документах Android четко показан используемый контекст приложения.Я всегда использовал контекст приложения для тостов из-за этого примера Google.Если это неправильно, то Google бросил мяч здесь.

Вот еще, о чем подумать и просмотреть:

Для сообщения с тостами в Руководстве разработчика по Google используется контекст приложения и явно сказано:чтобы использовать его: Уведомления Toast

В разделе диалогов руководства разработчика, вы видите, что AlertDialog.Builder использует контекст приложения, а затем индикатор выполнения использует контекст активности.Это не объясняется Google. Диалоги

Кажется, хорошей причиной для использования контекста приложения является ситуация, когда вы хотите обрабатывать изменения конфигурации, например, изменение ориентации, и вы хотите сохранить объекты, которым нужен контекст, такой как Views.Если вы посмотрите здесь: Изменения во время выполнения Существует предостережение относительно использования контекста активности, который может привести к утечке.Этого можно избежать с помощью контекста приложения с представлениями, которые должны быть сохранены (по крайней мере, это мое понимание).В приложении, которое я пишу, я намереваюсь использовать контекст приложения, потому что я пытаюсь удерживать некоторые представления и другие вещи при изменении ориентации, и я все еще хочу, чтобы действие было уничтожено и воссоздано при изменении ориентации.Поэтому я должен использовать контекст приложения, чтобы не вызывать утечку памяти (см. Предотвращение утечек памяти ).Мне кажется, есть много веских причин использовать контекст приложения вместо контекста активности, и мне кажется, что вы будете использовать его чаще, чем контекст активности.Это то, что делают многие книги по Android, которые я изучал, и это то, что делают многие примеры Google, которые я видел.

Документация Google действительно заставляет думать, что использование контекста приложения совершенно нормально в большинствеслучаи, и на самом деле появляется чаще, чем использование контекста активности в своих примерах (по крайней мере, примеры, которые я видел).Если использование контекста приложения на самом деле является такой проблемой, то Google действительно нужно уделять больше внимания этому.Им нужно прояснить это, и они должны переделать некоторые из своих примеров.Я бы не стал винить в этом неопытных разработчиков, поскольку авторитет (Google) действительно заставляет его выглядеть так, будто это не проблема использовать контексты приложения.

35 голосов
/ 04 февраля 2016

Я использовал эту таблицу как руководство для того, когда использовать различные типы контекста, такие как Контекст приложения (т.е.: getApplicationContext()) и контекст активности , также Контекст BroadcastReceiver :

enter image description here

Все заслуги переданы автору оригинала здесь для получения дополнительной информации.

11 голосов
/ 10 апреля 2014

Какой контекст использовать?

Существует два типа контекста:

  1. Контекст приложения связан сприложение и всегда будет одинаковым на протяжении всего срока действия приложения - оно не меняется.Поэтому, если вы используете Toast, вы можете использовать контекст приложения или даже контекст активности (оба), потому что toast может отображаться в любом месте вашего приложения и не привязано к определенному окну.Но есть много исключений, одно исключение - когда вам нужно использовать или передавать контекст действия.

  2. Контекст действия связан с действием и может быть уничтожен.если действие уничтожено - может быть несколько действий (более чем вероятно) с одним приложением.А иногда вам абсолютно необходим дескриптор контекста активности.Например, если вы запускаете новое действие, вам нужно использовать контекст действия в его намерении, чтобы новое действие запуска было связано с текущим действием с точки зрения стека действий.Однако вы также можете использовать контекст приложения для запуска нового действия, но затем вам нужно установить флаг Intent.FLAG_ACTIVITY_NEW_TASK, чтобы рассматривать его как новое задание.

Давайте рассмотрим некоторые случаи:

  • MainActivity.this относится к контексту MainActivity, который расширяет класс Activity, но базовый класс (активность) также расширяет класс Context, поэтому его можно использовать для предоставления контекста действия.

  • getBaseContext() предлагает контекст активности.

  • getApplication() предлагает контекст приложения.

  • getApplicationContext() такжепредлагает контекст приложения.

Для получения дополнительной информации, пожалуйста, проверьте эту ссылку .

4 голосов
/ 16 марта 2016

Мне было интересно, почему бы не использовать Application Context для каждой операции, которую он поддерживает.В конце концов, это снижает вероятность утечки памяти и пропускает нулевую проверку для getContext () или getActivity () (при использовании внедренного контекста приложения или при получении статическим методом из приложения).Заявления, как у Ms.Hackborn использовать контекст приложения только в случае необходимости, не кажется мне убедительным без объяснения причин.Но, похоже, я нашел несогласное, почему:

обнаружили, что существуют проблемы с некоторыми версиями Android / комбинациями устройств, которые не соответствуют этим правилам.Например, если у меня есть BroadcastReceiver, которому передан Контекст, и я преобразую этот Контекст в контекст приложения, а затем пытаюсь вызвать registerReceiver () в контексте приложения, есть много случаев, когда это работает нормально, но также много случаев, когда я получаюсбой из-за ReceiverCallNotAllowedException.Эти сбои происходят в широком диапазоне версий Android от API 15 до 22. https://possiblemobile.com/2013/06/context/#comment-2443283153

Поскольку не гарантируется, что все операции, описанные как поддерживаемые контекстом приложения в таблице ниже, будутработать на всех устройствах Android! enter image description here

3 голосов
/ 06 января 2014

Контекст приложения в реальном времени до тех пор, пока ваше приложение будет работать только , и оно не зависит от жизненного цикла действия, но контекст сохраняет объект долгоживущим .Если объект, который вы используете временно, в этот раз использует Контекст приложения и Контекст активности , то он полностью противоположен Контексту приложения.

3 голосов
/ 04 сентября 2011

Два замечательных примера использования контекста «Активность» по сравнению с контекстом приложения - при отображении сообщения Toast или встроенного диалогового окна, так как использование контекста приложения вызовет исключение:

ProgressDialog.show(this, ....);

или

Toast t = Toast.makeText(this,....);

Оба из них нуждаются в информации из контекста Activity, которая не предоставляется в контексте Application.

...