Какая разница между различными методами получения контекста?
В различных битах кода Android я видел:
public class MyActivity extends Activity {
public void method() {
mContext = this; // since Activity extends Context
mContext = getApplicationContext();
mContext = getBaseContext();
}
}
Однако я не могу найти подходящего объяснения, которое предпочтительнее и при каких обстоятельствах следует использовать.
Указатели на документацию по этому поводу и руководство о том, что может сломаться, если выбрано неправильное, будут очень оценены.
Ответы
Ответ 1
Я согласен с тем, что документация разрешена, когда дело доходит до контекстов в Android, но вы можете собрать несколько фактов из разных источников.
Это сообщение в блоге в официальном блоге разработчиков Google Android было написано в основном, чтобы помочь устранить утечки памяти, но также содержит некоторую полезную информацию о контекстах
В обычном приложении для Android вы обычно имеют два вида Контекста, Деятельность и применение.
Внимательно прочитав статью, мы расскажем о различии между этими двумя и когда вы захотите рассмотреть использование контекста приложения (Activity.getApplicationContext()
) вместо использования контекста Activity this
). В основном контекст приложения связан с Приложением и всегда будет одинаковым на протяжении всего жизненного цикла вашего приложения, где, поскольку контекст Activity связан с активностью и может быть многократно уничтожен по мере уничтожения активности во время изменений ориентации экрана и например.
Я не мог найти ничего о том, когда использовать getBaseContext(), кроме сообщения от Dianne Hackborn, одного из инженеров Google, работающих на Android SDK:
Не используйте getBaseContext(), просто используйте Контекст, который у вас есть.
Это было из сообщения в группе разработчиков Android-разработчиков, возможно, вам захочется рассмотреть вопрос и там, потому что несколько люди, работающие над Android, фактически контролируют эту группу новостей и отвечают на вопросы.
В общем случае предпочтительнее использовать глобальный контекст приложения, если это возможно.
Ответ 2
Вот что я нашел относительно использования context
:
1). В самом Activity
используйте this
для раздувания макетов и меню, регистрации контекстных меню, создания экземпляров виджета, запуска других действий, создания нового Intent
в Activity
, настройки экземпляров или другие методы, доступные в Activity
.
Развертывание макета:
View mView = this.getLayoutInflater().inflate(R.layout.myLayout, myViewGroup);
Надувное меню:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
this.getMenuInflater().inflate(R.menu.mymenu, menu);
return true;
}
Зарегистрировать контекстное меню:
this.registerForContextMenu(myView);
Создавать виджет:
TextView myTextView = (TextView) this.findViewById(R.id.myTextView);
Запустите Activity
:
Intent mIntent = new Intent(this, MyActivity.class);
this.startActivity(mIntent);
Мгновенные настройки:
SharedPreferences mSharedPreferences = this.getPreferenceManager().getSharedPreferences();
2). Для класса приложения используйте getApplicationContext()
, поскольку этот контекст существует для срока службы приложения.
Получить имя текущего пакета Android:
public class MyApplication extends Application {
public static String getPackageName() {
String packageName = null;
try {
PackageInfo mPackageInfo = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0);
packageName = mPackageInfo.packageName;
} catch (NameNotFoundException e) {
// Log error here.
}
return packageName;
}
}
Привязать класс приложения:
Intent mIntent = new Intent(this, MyPersistent.class);
MyServiceConnection mServiceConnection = new MyServiceConnection();
if (mServiceConnection != null) {
getApplicationContext().bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
3). Для прослушивателей и других типов классов Android (например, ContentObserver) используйте подстановку Context, например:
mContext = this; // Example 1
mContext = context; // Example 2
где this
или context
- это контекст класса (Activity и т.д.).
Activity
замена контекста:
public class MyActivity extends Activity {
private Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
}
}
Подстановка контекста слушателя:
public class MyLocationListener implements LocationListener {
private Context mContext;
public MyLocationListener(Context context) {
mContext = context;
}
}
ContentObserver
замена контекста:
public class MyContentObserver extends ContentObserver {
private Context mContext;
public MyContentObserver(Handler handler, Context context) {
super(handler);
mContext = context;
}
}
4). Для BroadcastReceiver
(включая встроенный/встроенный приемник) используйте собственный контекст получателя.
Внешний BroadcastReceiver
:
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
sendReceiverAction(context, true);
}
private static void sendReceiverAction(Context context, boolean state) {
Intent mIntent = new Intent(context.getClass().getName() + "." + context.getString(R.string.receiver_action));
mIntent.putExtra("extra", state);
context.sendBroadcast(mIntent, null);
}
}
}
Встроенный/встроенный BroadcastReceiver
:
public class MyActivity extends Activity {
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final boolean connected = intent.getBooleanExtra(context.getString(R.string.connected), false);
if (connected) {
// Do something.
}
}
};
}
5). Для служб используйте собственный контекст службы.
public class MyService extends Service {
private BroadcastReceiver mBroadcastReceiver;
@Override
public void onCreate() {
super.onCreate();
registerReceiver();
}
private void registerReceiver() {
IntentFilter mIntentFilter = new IntentFilter();
mIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
this.mBroadcastReceiver = new MyBroadcastReceiver();
this.registerReceiver(this.mBroadcastReceiver, mIntentFilter);
}
}
6). Для тостов обычно используйте getApplicationContext()
, но там, где это возможно, используйте контекст, переданный из Activity, Service и т.д.
Использовать контекст приложения:
Toast mToast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG);
mToast.show();
Использовать контекст, переданный из источника:
public static void showLongToast(Context context, String message) {
if (context != null && message != null) {
Toast mToast = Toast.makeText(context, message, Toast.LENGTH_LONG);
mToast.show();
}
}
И, наконец, не используйте getBaseContext()
, как сообщается разработчиками платформы Android.
UPDATE: Добавьте примеры использования context
.
Ответ 3
Я прочитал эту тему несколько дней назад, задавая себе тот же вопрос. Мое решение после прочтения было простым: всегда используйте applicationContext.
Однако у меня возникла проблема с этим, я потратил несколько часов, чтобы найти его, и несколько секунд, чтобы его решить... (изменение одного слова...)
Я использую LayoutInflater, чтобы раздуть представление, содержащее Spinner.
Итак, вот две возможности:
1)
LayoutInflater layoutInflater = LayoutInflater.from(this.getApplicationContext());
2)
LayoutInflater layoutInflater = LayoutInflater.from(this.getBaseContext());
Затем я делаю что-то вроде этого:
// managing views part
View view = ContactViewer.mLayoutInflater.inflate(R.layout.aViewContainingASpinner, theParentView, false);
Spinner spinner = (Spinner) view.findViewById(R.id.theSpinnerId);
String[] myStringArray = new String[] {"sweet","love"};
// managing adapter part
// The context used here don't have any importance -- both work.
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this.getApplicationContext(), myStringArray, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
theParentView.addView(view);
Что я заметил: если вы создали экземпляр linearLayout с помощью applicationContext, тогда, когда вы нажмете на spinner в своей деятельности, у вас будет неперехваченное исключение, исходящее из виртуальной машины dalvik (а не из вашего кода, поэтому у меня есть потратил много времени, чтобы найти, где была моя ошибка...).
Если вы используете baseContext, тогда все в порядке, откроется контекстное меню, и вы сможете выбрать один из своих вариантов.
Итак, вот мой вывод: я полагаю (я еще не тестировал его дальше), чем baseContext требуется при работе с contextMenu в вашей деятельности...
Тест был выполнен с использованием API 8 и протестирован на HTC Desire, Android 2.3.3.
Надеюсь, мой комментарий до сих пор вас не утомляет, и желаю вам всего наилучшего. Счастливое кодирование; -)
Ответ 4
Во-первых, я согласен с тем, что мы должны использовать appcontext, когда это возможно. затем "this" в действии. Я никогда не нуждался в basecontext.
В моих тестах в большинстве случаев они могут быть взаимозаменяемы. В большинстве случаев причиной, по которой вы хотите получить контекст, является доступ к файлам, настройкам, базе данных и т.д. Эти данные в конечном итоге отражаются как файлы в папке личных данных приложения (/data/data/). Независимо от того, какой контекст вы используете, они будут сопоставлены с одной и той же папкой/файлами, чтобы вы были в порядке.
То, что я наблюдал. Возможно, есть случаи, когда вы должны их отличать.
Ответ 5
В некоторых случаях вы можете использовать контекст Activity по контексту приложения при запуске чего-либо в потоке. Когда поток завершает выполнение и вам нужно вернуть результат обратно к активности вызывающего, вам нужен этот контекст с обработчиком.
((YourActivity) context).yourCallbackMethod(yourResultFromThread, ...);
Ответ 6
Простыми словами
getApplicationContext()
, поскольку предлагаемое имя метода позволит вашему приложению узнать о подробностях приложения, доступ к которым вы можете получить из любого места приложения. Таким образом, вы можете использовать это в привязке к сервису, регистрации вещания и т.д. Application context
будет оставаться до выхода приложения.
getActivity()
или this
сделает ваше приложение осведомленным о текущем экране, на котором видны также данные уровня приложения, предоставленные Application context
. Итак, что бы вы ни хотели узнать о текущем экране, например Window
ActionBar
Fragementmanger
, и поэтому доступны в этом контексте. В основном и Activity
расширяем Context
. Этот контекст будет живым до тех пор, пока не будет активен текущий компонент (активность)
Ответ 7
Я использовал только это и getBaseContext
при поджаривании с onClick
(очень зеленый noob для Java и Android). Я использую это, когда мой кликер находится непосредственно в действии и должен использовать getBaseContext
в анонимном внутреннем клиенте. Я предполагаю, что это довольно трюк с getBaseContext
, возможно, он возвращает контекст активности, в котором скрывается внутренний класс.
Ответ 8
Путаница проистекает из того факта, что существует множество способов доступа к Context, без видимых различий. Ниже приведены четыре наиболее распространенных способа доступа к контексту в действии.
getContext()
getBaseContext()
getApplicationContext()
getActionBar().getThemedContext() //new
Что такое контекст? Лично мне нравится думать о контексте как о состоянии вашего приложения в любой момент времени. Контекст приложения представляет собой глобальную или базовую конфигурацию вашего приложения, на которую может опираться действие или служба, и представляет экземпляр конфигурации вашего приложения или переходное состояние для него.
Если вы посмотрите на источник для android.content.Context, вы увидите, что Context является абстрактным классом, и комментарии к классу следующие:
Интерфейс для глобальной информации о среде приложения. Это абстрактный класс, реализация которого обеспечивается системой Android. Он позволяет получить доступ к ресурсам и классам, application-specific
к application-specific
, а также к дополнительным вызовам для операций на application-level
таких как запуск, широковещание и получение, и т.д. От этого я отказываюсь, так как Context предоставляет общую реализацию для доступа к приложению. уровень, а также ресурсы системного уровня. Ресурсы уровня приложения могут получать доступ к таким вещам, как String resources [getResources()]
или assets [getAssets()]
а ресурс системного уровня - это все, к чему вы Context.getSystemService().
с помощью Context.getSystemService().
На самом деле, посмотрите на комментарии к методам, и они, кажется, усиливают это понятие:
getSystemService()
: возвращает дескриптор службы system-level
по имени. Класс возвращаемого объекта зависит от запрошенного имени. getResources()
: возвращает экземпляр Resources для вашего пакета приложений. getAssets()
: возвращает экземпляр Resources для вашего пакета приложений. Возможно, стоит отметить, что в абстрактном классе Context все вышеперечисленные методы являются абстрактными! Только один экземпляр getSystemService (Class) имеет реализацию, которая вызывает абстрактный метод. Это означает, что реализация для них должна обеспечиваться в основном реализующими классами, которые включают в себя:
ContextWrapper
Application
Activity
Service
IntentService
Глядя на документацию по API, иерархия классов выглядит следующим образом:
контекст
| - ContextWrapper
| - - Применение
| - - ContextThemeWrapper
| - - - - Деятельность
| - - Обслуживание
| - - - IntentService
Поскольку мы знаем, что сам по себе Context
не дает никакой информации, мы перемещаемся по дереву и смотрим на ContextWrapper
и понимаем, что там тоже не так много. Поскольку Application расширяет ContextWrapper
, там тоже не на что смотреть, поскольку он не перекрывает реализацию, предоставляемую ContextWrapper
. Это означает, что реализация для контекста предоставляется ОС и скрыта от API
. Вы можете взглянуть на конкретную реализацию для Context, посмотрев на источник для класса ContextImpl.