在一个片段中使用上下文

739

如何在Fragment中获取上下文?

我需要使用需要上下文作为构造函数参数的数据库,但是getApplicationContext()FragmentClass.this都不起作用,那么我该怎么办?

数据库构造函数

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

1432
你可以使用getActivity(),它返回与fragment相关联的活动。
该活动是一个context(因为Activity扩展了Context

230
如果在相应片段的 onAttach 方法之前调用 getActivity(),则可能返回 null。请注意不改变原文意思并尽量简洁易懂。 - arne.jans
4
我正在阅读这篇有关内存泄漏的 Google 博客...http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html 。如果我使用 getActivity() 方法,应用程序是否会面临内存泄漏的风险?该博客建议“尝试使用 context-application 而不是 context-activity”,但由于 getApplicationContext() 仅适用于 Activity 类而不适用于 Fragment 类,因此并不太可能实现。 - Simon
49
当一个片段被创建时,解决脱离片段问题的方法是将 getActivity().getApplicationContext() 的值存储在一个实例变量中,然后在片段类中任何需要使用该上下文时都可以使用它。这个上下文将在片段分离后保留下来。 - Piovezan
10
在不传递应用程序上下文的情况下,创建一个静态上下文在您的Application类中,并在onCreate()函数中初始化: MyApplication.sContext = getApplicationContext(); 然后您可以从任何活动/片段访问它而不必担心分离。 - Eduard
4
“getActivity”一直可用。而“getContext”是在API 23中添加的。 - mhsmith
显示剩余7条评论

138

按照上面的答案,您可以重写片段的onAttach方法:

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

3
如果onAttach尚未被调用,getActivity()将返回null,因此我建议这么做。 - arne.jans
10
请注意,当调用onAttach()函数时,还没有视图可供使用。因此,您目前还不能对视图执行任何操作! - Zordid
2
@iambox 如果 DatabaseHelper 需要一个 FragmentActivity 而不是一个 Activity,那该怎么办呢?例如,在一个 Adapter 中… - Jago
4
如果您在onAttach(Activity activity)中存储了对您的活动的引用,则应在onDetach()中释放它。 - vovahost
3
"onAttach" 方法已被弃用,"Overrides deprecated method in 'android.support.v4.app.Fragment'"。 (注:意思是该方法被废弃了,需使用其他方法代替。同时,代码中出现了警告,提示该方法已经被弃用,需要修改代码以避免出现问题。) - Muhammad Saqib
显示剩余2条评论

29

我发现获取片段上下文最简单和最精确的方法是在调用 onCreateView 方法时直接从 ViewGroup 中获取,至少在这里您可以确保不会得到 getActivity() 的null值:

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

10
那是容器的上下文,我想...不是"这个上下文"。 - Fattie
2
@AG1能否请您解释一下为什么它会崩溃您的代码?这是目前我得到的最佳解决方案。 - Machado
4
实际上,在DialogFragment中,容器可能为空。要小心! - Lucas Teske
这个解决方案应该在onViewCreated中使用,而不是在onCreateView中使用。 - fisio

26

使用getActivity()方法来获取所依附的活动的上下文,但需要记住一点:片段(Fragments)有些不稳定,getActivity()有时会返回null,因此在使用getActivity()之前,请始终检查片段的isAdded()方法。


17
我不会说片段是“稍微不稳定的”,当片段不属于活动时,getActivity() 返回 null 是很正常的。假设 getActivity() “不应该返回 null”(这是错误的),才会使您的应用程序(而不是 Fragment 类)不稳定。 - personne3000
3
@personne3000,我很乐意听更多。何时一个片段不属于活动?这是什么时候发生的,为什么?我们应该在片段中检查isAdded()以便使用getActivity()吗?有什么经验法则吗? - Sotti
2
@Sotti,我鼓励你为此创建一个新问题(或查找现有问题),因为这个特定的主题与原始问题有些不同。您可以查看http://developer.android.com/guide/components/fragments.html#Lifecycle获取一般信息。基本上,在onAttach之前和onDetach之后,没有活动。在onAttach和onActivityCreated之间,活动的onCreate尚未被调用。使用getActivity()时,请确保您的活动已经创建,并考虑如果它被销毁或您的片段被分离会发生什么。 - personne3000

25

正确的方法是使用

requireContext()

以及这个例子

ContextCompat.getColor(requireContext(), R.color.colorAccent),

上下文 != 应用程序上下文 - Gabriele Mariotti
requireContext()可能会抛出异常时,它如何被认为是正确的?我认为这是一种有害的使用方式。 - YaMiN
@YaMiN,这是正确的,因为你应该熟悉生命周期,这样你只在不会抛出异常的时候调用它。如果你在这方面犯了错误,你希望它能够快速失败,这样你就可以立即在测试中捕获到错误。你将得到比NullPointerException更有用的异常信息。 - undefined

19

之前我在Fragment中使用onAttach(Activity activity)来获取context

问题

onAttach(Activity activity)方法在API级别23中已被弃用。

解决方案

现在我们可以使用onAttach(Context context)来获取Fragment中的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;
    }

}

注意

Fragments中,我们也可以使用getActivity()来获取context,但是如果您的fragment当前未附加到父activity,则getActivity()可能会返回null


是的,这是一个不错的解决方案,但需要测试各种情况。 - Daxesh Vekariya

14

requireContext()方法是最简单的选项

requireContext()

例子

MyDatabase(requireContext())

12
@Override
public void onAttach(Activity activity) {
    // TODO Auto-generated method stub
    super.onAttach(activity);
    context=activity;
}

7

当重写onCreateView时,您还可以从inflater参数中获取上下文。

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

5

另一种替代方法是:

您可以使用以下方式获取上下文:

getActivity().getApplicationContext();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接