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


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

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

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

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

7 365

7 ответов:

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

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

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

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

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

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

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

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

вот что я нашел относительно использования context:

1) . внутри используйте 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);

Instantiate preferences:

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 контекст замены:

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

использовать контекст приложения:

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 для раздувания представления, содержащего спиннер.

Так вот два возможности:

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

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

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

тест был сделан кодирование с API 8,и протестирован на HTC Desire, android 2.3.3.

Я надеюсь, что мой комментарий не скучно до сих пор, и желаю вам всего наилучшего. Счастливый кодирование ; -)

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

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

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

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

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

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

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

getActivity() или this сделает ваше приложение в курсе текущего экрана, который виден также детали уровня приложения, предоставляемые application context. Так что вы хотите знать о текущий экран как WindowActionBarFragementmanger и так доступны с этим контекстом. В принципе и Activity расширения Context. Этот контекст будет жив, пока текущий компонент (activity) не будет жив

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