В чем разница между различными методами получения контекста?

StackOverflow https://stackoverflow.com/questions/1026973

  •  06-07-2019
  •  | 
  •  

Вопрос

В различных частях кода Android я видел:

 public class MyActivity extends Activity {
    public void method() {
       mContext = this;    // since Activity extends Context
       mContext = getApplicationContext();
       mContext = getBaseContext();
    }
 }

Однако я не могу найти достойного объяснения того, что предпочтительнее и при каких обстоятельствах следует использовать.

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

Это было полезно?

Решение

Я согласен с тем, что документация скудна, когда дело доходит до контекстов в Android, но вы можете собрать воедино несколько фактов из различных источников.

Это сообщение в блоге на официальном Google Android Блог разработчиков был написан в основном для устранения утечек памяти, но также предоставляет некоторую полезную информацию о контекстах:

  

В обычном приложении Android вы   обычно имеют два вида контекста,   Активность и применение.

Чтение статьи чуть дальше расскажет о разнице между ними и о том, когда вы можете рассмотреть возможность использования контекста приложения ( Activity.getApplicationContext () ) вместо использования контекста Activity это ). По сути, контекст приложения связан с приложением и всегда будет одинаковым на протяжении жизненного цикла вашего приложения, поскольку контекст действия связан с действием и может быть уничтожен много раз, так как действие разрушается во время изменения ориентации экрана и например.

Я не смог найти ничего о том, когда использовать getBaseContext (), кроме сообщения от Дайан Хэкборн, одного из инженеров Google, работающего над Android SDK:

  

Не используйте getBaseContext (), просто используйте   Контекст у вас есть.

Это было из сообщения в группа новостей android-developers , возможно, вы захотите задать свой вопрос и там, потому что горстка людей, работающих на Android, контролируют эту группу новостей и отвечают на вопросы.

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

Другие советы

Вот что я нашел относительно использования 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);

Начать действие :

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) используйте подстановку контекста, например:

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-платформ.

ОБНОВЛЕНИЕ: Добавьте примеры использования Context .

Прочитал эту тему несколько дней назад и задался тем же вопросом.Мое решение после прочтения было простым:всегда используйте 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);

Что я заметил:Если вы создали экземпляр своего линейного макета с помощью applicationContext, то когда вы нажимаете на счетчик в своей деятельности, у вас будет неперехваченное исключение, исходящее из виртуальной машины dalvik (а не из вашего кода, поэтому я потратил много времени, чтобы найти где была моя ошибка...).

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

Итак, вот мой вывод:Я полагаю (я не проверял это дальше), чем требуется baseContext при работе с contextMenu в вашей деятельности...

Тест проводился с использованием API 8 и тестировался на HTC Desire, Android 2.3.3.

Надеюсь, мой комментарий вам еще не наскучил, и желаю вам всего наилучшего.Приятного кодирования ;-)

Во-первых, я согласен, что мы должны использовать appcontext, когда это возможно. тогда "это" в деятельности. у меня никогда не было необходимости в базовом контексте.

В моих тестах в большинстве случаев их можно менять местами. В большинстве случаев причиной, по которой вы хотите получить контекст, является доступ к файлам, настройкам, базе данных и т. Д. Эти данные в конечном итоге отражаются в виде файлов в папке личных данных вашего приложения (/ data / data /). Независимо от того, какой контекст вы используете, они будут сопоставлены с одной и той же папкой / файлами, так что вы в порядке.

Это то, что я заметил. Возможно, есть случаи, которые вы должны различать.

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

((YourActivity) context).yourCallbackMethod(yourResultFromThread, ...);

Простыми словами

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

getActivity () или this информирует ваше приложение о текущем экране, который также виден, и сведения об уровне приложения, предоставляемые контекстом приложения , Поэтому все, что вы хотите знать о текущем экране, например Window ActionBar Fragementmanger и так далее, доступно в этом контексте. В основном и Activity расширяют Context . Этот контекст будет активен до тех пор, пока текущий компонент (активность) не будет активен

Я использовал это и getBaseContext только для тостов из onClick (очень зеленый нуб как для Java, так и для Android). Я использую это, когда мой кликер находится непосредственно в действии и должен использовать getBaseContext в анонимном внутреннем кликере. Я предполагаю, что это в значительной степени хитрость с getBaseContext , возможно, он возвращает контекст действия, в котором скрывается внутренний класс.

Путаница проистекает из того факта, что существует множество способов получить доступ к контексту, причем (на поверхности) нет заметных различий.Ниже приведены четыре из наиболее распространенных способов получить доступ к контексту в деятельности.

getContext()
getBaseContext()
getApplicationContext()
getActionBar().getThemedContext() //new

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

Если вы посмотрите исходный код android.content.Context, то увидите, что Context — это абстрактный класс, а комментарии к классу следующие:

Интерфейс для глобальной информации о среде приложения.Это абстрактный класс, реализация которого обеспечивается системой Android.Это позволяет получить доступ к application-specific ресурсы и классы, а также призывы к application-level такие операции, как запуск действий, намерения трансляции и приема и т. д.Что я извлек из этого, так это то, что Context предоставляет общую реализацию для доступа на уровне приложения, а также к ресурсам системного уровня.Ресурсы уровня приложения могут иметь доступ к таким вещам, как строковые ресурсы. [getResources()] или активы [getAssets()] а ресурс системного уровня — это все, к чему вы получаете доступ Context.getSystemService().

На самом деле, взгляните на комментарии к методам, и они, похоже, подтверждают это мнение:

getSystemService():Верните ручку в system-level услуга по имени.Класс возвращаемого объекта зависит от запрошенного имени.getResources():Верните экземпляр Resources для пакета вашего приложения.getAssets():Верните экземпляр Resources для пакета вашего приложения.Возможно, стоит отметить, что в абстрактном классе Context все вышеперечисленные методы являются абстрактными!Только один экземпляр getSystemService(Class) имеет реализацию и вызывает абстрактный метод.Это означает, что их реализация должна обеспечиваться в основном реализующими классами, которые включают в себя:

ContextWrapper
Application
Activity
Service
IntentService

Глядя на документацию API, иерархия классов выглядит следующим образом:

Контекст

| — КонтекстWrapper

|— — Приложение

| — — ContextThemeWrapper

|— — — — Деятельность

| — — Сервис

|— — — IntentService

Поскольку мы знаем, что Context сам по себе не дает никакой информации, мы спускаемся по дереву и смотрим на ContextWrapper и осознать, что там тоже ничего особенного.Поскольку приложение расширяет ContextWrapper, там тоже не на что смотреть, поскольку он не отменяет реализацию, предоставленную ContextWrapper.Это означает, что реализация контекста предоставляется ОС и скрыта от API.Вы можете взглянуть на конкретную реализацию Context, просмотрев исходный код класса ContextImpl.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top