Использование контекста во фрагменте


664

Как я могу получить контекст во фрагменте?

Мне нужно использовать свою базу данных, чей конструктор принимает в контексте, но так getApplicationContext()и FragmentClass.thisне работает, что я могу сделать?

Конструктор базы данных

public Database(Context ctx)
{
    this.context = ctx;
    DBHelper = new DatabaseHelper(context);
}

Ответы:


1314

Вы можете использовать getActivity(), который возвращает активность, связанную с fragment.
Активность является context (поскольку Activityрасширяется Context) .


212
getActivity () может вернуть значение null, если оно вызывается перед onAttach соответствующего фрагмента.
arne.jans

4
Я читал этот блог Google на утечки памяти ... android-developers.blogspot.com/2009/01/… . Если я использую метод getActivity (), не будет ли приложение подвержено риску утечки памяти? Блог предлагает «Попробуйте использовать контекстное приложение вместо контекстной активности», что на самом деле невозможно, так как getApplicationContext () работает только для класса Activity, а не для класса Fragment.
Симон

40
Решением проблемы отсоединенных фрагментов является сохранение значения getActivity().getApplicationContext()переменной экземпляра при создании фрагмента, а затем использование этого контекста всякий раз, когда вы хотите внутри класса фрагмента. Этот контекст переживет фрагменты отрядов.
Пиовезан

8
Вместо передачи контекста приложения создайте статический контекст внутри класса Application и инициализируйте его onCreate (): MyApplication.sContext = getApplicationContext (); тогда вы можете получить к нему доступ из любого действия / фрагмента, не беспокоясь об отрыве.
Эдуко

3
@milaniez: getActivityвсегда был доступен. Это getContextбыло добавлено в API 23.
Mhsmith

130

Чтобы сделать ответ выше, вы можете переопределить onAttachметод фрагмента:

public static class DummySectionFragment extends Fragment{
...
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        DBHelper = new DatabaseHelper(activity);
    }
}

3
Я бы порекомендовал это, так как getActivity () возвращает ноль, если onAttach еще не вызван.
arne.jans

9
Но имейте в виду, что при вызове onAttach () представления отсутствуют. Так что вы ничего не можете сделать с представлениями еще!
Зордид

2
@iambox, что если DatabaseHelperнужно FragmentActivityвместо Activity? Например, для Adapter...
Jago

4
Если вы храните ссылку на вашу деятельность в, onAttach(Activity activity)то вы должны выпустить ее вonDetach()
vovahost

3
onAttachМетод устарел,Overrides deprecated method in 'android.support.v4.app.Fragment'
Мухаммад Saqib

24

Всегда используйте метод getActivity () для получения контекста вашей прикрепленной активности, но всегда помните одну вещь: фрагменты немного нестабильны и getActivityвозвращают null несколько раз, поэтому для этого всегда проверяйте метод фрагмента isAdded () перед получением контекста getActivity().


15
Я бы не сказал, что фрагменты «немного нестабильны», вполне нормально, что getActivity () возвращает ноль, когда фрагмент не принадлежит действию. Предполагается, что getActivity () «не должна возвращать ноль» (что неверно), что сделает ваше приложение (а не класс Fragment) нестабильным.
personne3000

3
@ personne3000 Я хотел бы услышать больше. Когда фрагмент не принадлежит Деятельности? Когда это происходит и почему? Должны ли мы проверять isAdded () во фрагменте, чтобы использовать getActivity ()? Любое эмпирическое правило?
Сотти

2
@ Сотти Я призываю вас создать новый вопрос для этого (или искать уже существующий), поскольку этот конкретный вопрос немного отличается от исходного вопроса. Вы можете взглянуть на developer.android.com/guide/components/fragments.html#Lifecycle для получения общей информации. В основном, до onAttach и после onDetach, нет активности. А между onAttach и onActivityCreated действие onCreate еще не было вызвано. При использовании getActivity () убедитесь, что ваша деятельность уже создана, и подумайте, что произойдет, если она будет уничтожена или ваш фрагмент был отсоединен.
personne3000

22

Самый простой и точный способ получить контекст фрагмента, который я нашел, это получить его непосредственно из того, ViewGroupкогда вы вызываете onCreateViewметод, по крайней мере, здесь вы точно не получите null для getActivity():

public class Animal extends Fragment { 
  Context thiscontext;
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
  {
    thiscontext = container.getContext();

10
это контекст контейнера, я думаю ... а не "этот контекст".
Толстяк

2
@ AG1, не могли бы вы объяснить, почему он разбил ваш код? Это пока лучшее решение, которое у меня есть
Мачадо

3
На самом деле на dialogFragments контейнер может быть нулевым. Будь осторожен!
Лукас Теске

Это решение следует использовать в onViewCreated, а не в OnCreateView.
Андреа Де Симоне

13

Ранее я использую, onAttach (Activity activity)чтобы попасть contextвFragment

проблема

onAttach (Activity activity)Метод был устаревшим в уровне API 23.

Решение

Теперь, чтобы получить контекст, Fragmentмы можем использоватьonAttach (Context context)

onAttach (Context context)

  • Вызывается, когда фрагмент впервые присоединяется к его context. onCreate(Bundle)будет вызван после этого.

Документация

/**
 * Called when a fragment is first attached to its context.
 * {@link #onCreate(Bundle)} will be called after this.
 */
@CallSuper
public void onAttach(Context context) {
    mCalled = true;
    final Activity hostActivity = mHost == null ? null : mHost.getActivity();
    if (hostActivity != null) {
        mCalled = false;
        onAttach(hostActivity);
    }
}

ОБРАЗЕЦ КОДА

public class FirstFragment extends Fragment {


    private Context mContext;
    public FirstFragment() {
        // Required empty public constructor
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mContext=context;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rooView=inflater.inflate(R.layout.fragment_first, container, false);

        Toast.makeText(mContext, "THIS IS SAMPLE TOAST", Toast.LENGTH_SHORT).show();
        // Inflate the layout for this fragment
        return rooView;
    }

}

НОТА

Мы также можем использовать , getActivity()чтобы получить contextв Fragments но getActivity()может вернуться , nullесли ваше fragmentнастоящее время не прилагается к родителю activity,



6

Вы также можете получить контекст из inflaterпараметра при переопределении onCreateView.

public static class MyFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
        /* ... */
        Context context = inflater.getContext();
        /* ... */
    }
}

5

Другой альтернативный подход:

Вы можете получить контекст, используя:

getActivity().getApplicationContext();

5

получить контекст внутри фрагмента можно будет с помощью getActivity():

public Database()
{
    this.context = getActivity();
    DBHelper = new DatabaseHelper(this.context);
}
  • Будьте осторожны, чтобы Activityсвязать фрагмент с помощью getActivity(), вы можете использовать его, но не рекомендуется, это приведет к утечкам памяти.

Я думаю, что лучший подход должен получить Activityот onAttach()метода:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    context = activity;
}

Вы не должны использовать getActivity во фрагменте, чтобы получить представление, если это представление не является частью действия в любом случае. Зачем вам раздувать вид фрагмента, а потом даже не ссылаться на него?
tyczj

Этот ответ о другом, вы говорите о том, какое представление hiearchy для поиска представлений в. Activity.findViewByIdЭто просто удобный метод для поиска представления в зарегистрированном представлении содержимого этого действия (задано через setContentView). В вашем правильном примере вы вызываете View.findViewById, Activity.findViewByIdа не вызываете метод в правильном корневом представлении. Совершенно другая проблема, и, очевидно, вы не сможете найти свое представление в иерархии представлений, которая не поддерживает это представление.
JHH

3

getContext() появился в API 23. Замените его на getActivity () везде в коде.

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


3

Поскольку уровень API 23 существует, getContext()но если вы хотите поддерживать более старые версии, вы можете использовать их, getActivity().getApplicationContext()хотя я все еще рекомендую использовать версию поддержки, Fragmentкоторая есть android.support.v4.app.Fragment.


2

getActivity() это ребенок контекста, так что должен работать на вас


2

Использовать фрагменты из библиотеки поддержки -

android.support.v4.app.Fragment

а затем переопределить

void onAttach (Context context) {
  this.context = context;
}

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


2

У вас есть разные варианты:

  • Если ваш minSDK <= 21, то вы можете использовать getActivity(), так как это Context.
  • Если ваш minSDK> = 23, вы можете использовать getContext().

Если вам не нужно поддерживать старые версии, тогда используйте getContext().


2

Для Kotlin вы можете использовать contextнепосредственно во фрагментах. Но в некоторых случаях вы найдете ошибку, как

Несоответствие типов: предполагаемый тип - это Контекст? но контекст ожидался

для этого вы можете сделать это

val ctx = context ?: return
textViewABC.setTextColor(ContextCompat.getColor(ctx, android.R.color.black))

Спасибо за использование версии Kotlin, которая работает нормально, однако я пытаюсь получить Context для Picasso.get (), с ним, и он никогда не работает, я попробовал все, что я могу из примеров выше, чтобы получить контекст. В лучшем случае я получаю это сообщение -Слишком много аргументов передано ... Пожалуйста, помогите. val ctx = context?: вернуть Picasso.get (ctx) .load (selectedGallery.imageUrl) .placeholder (R.mipmap.ic_launcher) .into (galleryImage)
Ade

@Ade В своем фрагменте попробуйте использовать "активность !!" вместо "ctx", и дайте мне знать, помогает это или нет
Кишан Соланки

@ KishanSolanki124. Большое спасибо за быстрый ответ. Я попробовал ваше предложение, с тем же результатом - не работает до сих пор. Точное сообщение об ошибке: слишком много аргументов для публичного открытого веселья get (): Picasso !. Это сообщение заставляет меня задуматься, может быть, что-то еще является ошибкой? Однако я с радостью нашел способ продолжить работу с помощью Пикассо, не разбираясь в контексте. Еще раз спасибо.
Ade



1

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

Затем: вы можете разыменовать фрагмент для получения действия, контекста или контекста приложения по своему желанию:

this.getActivity()даст вам дескриптор действия this.getContext()даст вам дескриптор к контексту this.getActivity().getApplicationContext()даст вам дескриптор к контексту приложения. Желательно использовать контекст приложения при передаче его в БД.


1

Простой способ заключается в использовании getActivity(). Но я думаю, что основная путаница в использовании getActivity()метода для получения контекста здесь - исключение нулевого указателя.

Для этого сначала сверьтесь с isAdded()методом, который определит, добавлен он или нет, а затем мы сможем использовать getActivity()контекст, чтобы получить контекст Activity.


1
Чем это отличается от ответа Анкура Чаудхари ?
Питер Мортенсен

1

Вы можете позвонить getActivity()или,

public void onAttach(Context context) {
    super.onAttach(context);
    this.activity = (CashActivity) context;
    this.money = this.activity.money;
}

1

Вы можете использовать метод getActivity () для получения контекста или использовать метод getContext ().

 View root = inflater.inflate(R.layout.fragment_slideshow, container, false);
    Context c = root.getContext();

Я надеюсь, что это помогает!


1
Есть другие ответы, которые предоставляют вопрос ОП, и они были опубликованы некоторое время назад. При публикации ответа смотрите: Как мне написать хороший ответ? Пожалуйста, убедитесь, что вы добавили либо новое решение, либо существенно лучшее объяснение, особенно когда отвечаете на старые вопросы.
help-info.de


0

Я думаю, что вы можете использовать

public static class MyFragment extends Fragment {
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

      Context context = getActivity.getContext();

  }
}

0
public class MenuFragment extends Fragment implements View.OnClickListener {
    private Context mContext;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        FragmentMenuBinding binding=FragmentMenuBinding.inflate(inflater,container,false);
        View view=binding.getRoot();
        mContext=view.getContext();
        return view;
    }
}

0

Также вы можете использовать:

inflater.getContext();

но я бы предпочел использовать

getActivity()

или

getContext

0

Мне нужен контекст для использования массива IN фрагмент IN, когда я использовал getActivity ошибка, но когда я заменяю его на getContext, он работает для меня

listView LV=getView().findViewById(R.id.listOFsensors);
LV.setAdapter(new ArrayAdapter<String>(getContext(),android.R.layout.simple_list_item_1 ,listSensorType));

0

Вы можете использовать getActivity()или getContextво фрагменте.

Документация

/**
 * Return the {@link FragmentActivity} this fragment is currently associated with.
 * May return {@code null} if the fragment is associated with a {@link Context}
 * instead.
 *
 * @see #requireActivity()
 */
@Nullable
final public FragmentActivity getActivity() {
    return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}

а также

 /**
     * Return the {@link Context} this fragment is currently associated with.
     *
     * @see #requireContext()
     */
    @Nullable
    public Context getContext() {
        return mHost == null ? null : mHost.getContext();
    }

Pro tip

Всегда проверяйте, if(getActivity!=null)потому что он может быть нулевым, если фрагмент не привязан к действию. Иногда выполнение длительной операции во фрагменте (например, выборка данных из остальных API) занимает некоторое время. и если пользователь перейдет к другому фрагменту. Тогда getActivity будет нулевым. И вы получите NPE, если не справитесь.


Это документация по методу getActivity (), просто чтобы показать, что они могут быть нулевыми. Здесь mHost является экземпляром FragmentHostCallbackкласса.
Хемрай

0

На тебе фрагмент

((Name_of_your_Activity) getActivity()).helper

По активности

DbHelper helper = new DbHelper(this);

0

Внутренний фрагмент для образца kotlin помог бы кому-то

textViewStatus.setTextColor(ContextCompat.getColor(context!!, R.color.red))

если вы используете привязку данных;

bindingView.textViewStatus.setTextColor(ContextCompat.getColor(context!!, R.color.red))

Где bindingView инициализируется в onCreateView, как это

private lateinit var bindingView: FragmentBookingHistoryDetailBinding

bindingView = DataBindingUtil.inflate(inflater, R.layout.your_layout_xml, container, false)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.