Когда вызывать контекст активности или контекст приложения?

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

Как я понимаю до сих пор: Каждый из них является экземпляром его класса, что означает, что некоторые программисты рекомендуют вам использовать this.getApplicationContext() как можно чаще, чтобы не "утечка" какой-либо памяти. Это связано с тем, что другой this (получение контекста экземпляра Activity) указывает на Activity, который уничтожается каждый раз, когда пользователь наклоняет телефон или покидает приложение и т.д. Который, по-видимому, сборщик мусора (GC) 't ловить и, следовательно, использует слишком много памяти.

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

Ответ 1

getApplicationContext() почти всегда ошибочно. Г-жа. Hackborn (среди прочего) были очень явными, что вы используете только 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 и нашел, что это болезненно. Госпожа. Хакборн также согласен с этой позицией.

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

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

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

Ответ 2

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

Здесь больше задуматься и посмотреть:

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

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

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

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

Ответ 3

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

enter image description here

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

Ответ 4

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

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

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

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

Рассмотрим некоторые случаи:

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

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

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

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

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

Ответ 5

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

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

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

Ответ 6

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

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

или

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

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

Ответ 7

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