1.在Fragment中找到getContext()方法如下:

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

2.由上述可知当mHost == null 或者 mHost.getContext() =null
两种情况下会导致返回null.

对此需分析mHost是什么?

(1) Fragment中mHost的变量

	// Activity this fragment is attached to.
    @UnsupportedAppUsage
    FragmentHostCallback mHost;

(2) 查找mHost在什么地方赋值

I.优先参考: [正向调用过程的逻辑梳理]
通过源码解析 Fragment 启动过程
https://www.jianshu.com/p/f2fcc670afd6
获取整体性的认知

II.辅助参考:[逆向结果推原因的逻辑梳理]
Fragment中getContext得到的context从哪来?
https://blog.csdn.net/XG1057415595/article/details/82595248
看如何反推

我们的fragment一般是通过FragmentManager的beginTransaction方法得到FragmentTransaction然后add添加,而我们getSupportFragmentManager获取到
的是FragmentManagerImpl, 也就是FragmentManager的实现类,我们看FragmentManagerImpl的beginTransaction方法:

	@Override
    public FragmentTransaction beginTransaction() {
        return new BackStackRecord(this);

可以看到我们得到的FragmentTransaction是一个BackStackRecord对象,该类继承自FragmentTransaction;
而BackStackRecord的add方法最终还是回到FragmentManagerImpl的addFragment方法(涉及的fragment启动过程参考上述I);

二.为什么Fragment中的getContext()有时会返回null?

  1. 参考:
    (1)
    关于android:为什么片段中的getContext()有时会返回null?
    https://www.codenong.com/47987649/
    (2)Fragment 中使用 getActivity()为null的原因—剖析源码
    https://www.cnblogs.com/tingtasia/p/11545014.html
    (2+)Fragment中调用getActivity为null的问题---------------->Activity与Fragment的调用关系
    https://blog.csdn.net/ly969434341/article/details/107247332
    (3)Android System——事件传递(一) View
    https://www.jianshu.com/p/0b05c7fe24f9
  2. 实验性demo:
    参见:FragmentAndActivity.工程
  3. 一种猜想性推论?
    当transition的commit提交到消息队列,未被执行时, Fragment就没有mHost中含有的Activity;
    此时若Fragment中的onCreateView等方法执行完毕, button被注册onClickListener;并点击后,点击事件进入到消息队列.
    如果先执行了点击的消息就会产生Activity为null的问题.
    _ >针对此猜测,并不成立,
    _ >因为commit提交在前,点击事件提交在后.在主线程的消息队列中若没有特殊指定延时,会先执行前面提交的事件.
    _ >可参考: Android应用程序消息处理机制(Looper、Handler)分析
  4. (3+)可代码验证的一种问题情况
    (1) 由于一个应用中的一个Activity被销毁的时候;该应用进程没有被销毁;
    与主线程相关联的消息队列也没有被销毁.
    (2) 若之前该button上发生的点击事件进入了消息队列,而没有被消费掉.
    (3)此时,该button所在Fragment的Activity,因为(a)旋转配置发生改变,或(b)长时间放置内存不足被系统回收; 销毁后.
    (4)当消息队列中,未被消费的消息执行的时候,若消息中含有需要getActivity()这样的逻辑,就会报空指针异常.
    (5) 示例代码:

Fragment:

public class BlankFragment extends Fragment {
	Button button;
    int count = 0;
	@Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        Log.e(TAG, "onViewCreated_savedInstanceState " + savedInstanceState);
        Log.e(TAG, "onViewCreated_fragment " + this);
        Log.e(TAG, "onViewCreated_activity " + getContext());
        button = view.findViewById(R.id.test);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//                doSomeThing();
                count ++;
                Log.e(TAG, "count = " + count);
                button.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getActivity(), "count = " + count, Toast.LENGTH_LONG).show();
                }, count * 1000);
    @Override
    public void onDetach() {
        super.onDetach();
        Log.e(TAG, "onDetach_fragment " + this);
        Log.e(TAG, "onDetach_activity " + getContext());
        Log.e(TAG, "onDetach_OnClickListener_before_remove " + getOnClickListener(button));
        removeOnClickListener(button);
        Log.e(TAG, "onDetach_OnClickListener_after_remove " + getOnClickListener(button));
	private <T> Method  getDeclaredMethod(Object obj, String methodName) {
        Method method = null;
        Class clazz = obj.getClass();
        while (clazz != Object.class) {
            try {
                method = clazz.getDeclaredMethod(methodName);
                return method;
            } catch (Exception e) {
            clazz = clazz.getSuperclass();
        return null;
    private Object getListenerInfo(View view) {
        Method method = getDeclaredMethod(view, "getListenerInfo");
        method.setAccessible(true);
        Object info = null;
        try {
            info = method.invoke(view);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        return info;
    private View.OnClickListener  getOnClickListener(View view) {
        Object info = getListenerInfo(view);
        View.OnClickListener result = (View.OnClickListener)
                getFieldValue(info, "mOnClickListener");
        return result;
    private void removeOnClickListener(View view) {
        Object info = getListenerInfo(view);
        setFiledValue(info, "mOnClickListener", null);
    private Object getFieldValue(Object obj, String fieldName) {
        if (obj == null || fieldName.isEmpty()) {
            return null;
        Class clazz = obj.getClass();
        if (clazz != Object.class) {
            try {
                Field field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                return field.get(obj);
            } catch (Exception e) {
        return null;
    private void setFiledValue(Object obj, String fieldName, Object value) {
        if (obj == null || fieldName.isEmpty()) {
            return;
        Class clazz = obj.getClass();
        while (clazz != Object.class) {
            Field field = null;
            try {
                field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                field.set(obj, value);
                return;
            } catch (Exception e) {
                e.printStackTrace();

Activity:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e(TAG, "MainActivity_onCreate_activity " + this);
        setContentView(R.layout.activity_main);
        Fragment fragment = new BlankFragment();
        Log.e(TAG, "MainActivity_onCreate_new_fragment " + fragment);
        addFragmentIfNotExist(getFragmentManager(), fragment);
        getMainLooper().getQueue();
    private void addFragmentIfNotExist(FragmentManager fm, Fragment f) {
        String tag = f.getClass().getName();
        Fragment old = fm.findFragmentByTag(tag);
        Log.e(TAG, "MainActivity_onCreate_old_fragment " + old);
        if (old == null) {
            FragmentTransaction transaction = fm.beginTransaction();
            transaction.add(android.R.id.content, f, tag);
            transaction.commit();

(6) 运行后上述代码, 点击按钮, 旋转屏幕后报的异常问题:

2021-02-09 19:03:06.587 2359-2359/com.test.fragmentandactivity E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.test.fragmentandactivity, PID: 2359
java.lang.NullPointerException: Attempt to invoke virtual method ‘java.lang.String android.content.Context.getPackageName()’ on a null object reference
at android.widget.Toast.(Toast.java:117)
at android.widget.Toast.makeText(Toast.java:280)
at android.widget.Toast.makeText(Toast.java:270)
at com.test.fragmentandactivity.BlankFragment$1 1.run(BlankFragment.java:112) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:201) at android.app.ActivityThread.main(ActivityThread.java:6806) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit 1.run(BlankFragment.java:112)atandroid.os.Handler.handleCallback(Handler.java:873)atandroid.os.Handler.dispatchMessage(Handler.java:99)atandroid.os.Looper.loop(Looper.java:201)atandroid.app.ActivityThread.main(ActivityThread.java:6806)atjava.lang.reflect.Method.invoke(NativeMethod)atcom.android.internal.os.RuntimeInitMethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)

(6) 问题的解决方法
(a)对于需要进入到消息队列中执行的代码,不要使用getActivity()去获取Context,而应该直接传递到参数中,使用入参Context.
(b) 对于在Activity或Fragment销毁的时候, 清除button的Listener的修复方法,应该是无效的.

一.Fragment中调用getContext()实际调用了什么?1.在Fragment中找到getContext()方法如下: /** * Return the {@link Context} this fragment is currently associated with. */ public Context getContext() { return mHost == null ? null : mHost.getContext(); }
这两天在研究插件化编程,在使用 Fragment 碰到了一些问题,于是查看源码,顺便分析了一下 FragmentFragmentManager 以及其他几个 API 的原代码,看看他们是怎么工作的。 我们知道 Fragment 有个 onCreateView() 方法,这个方法在 Fragment 创建 View 的时候被调用,并且返回一个 View 对象。那么 onCreateView 在什么时候被调用呢,咱们在 Fragment 这个类里找到了一个方法,performCreateView() 方法。 Fragment.java public View onCreateView(La
今天在改上一篇的bug(android.support.v4.app.Fragment$InstantiationException)时又发现了一个问题,经过实验得出结果.    Fragment获取Activity的Context时只需要this.getActivity()即可.     而不是许多人说的this.getActivity().getApplicationContext()
SecurityContextHolder.getContext().getAuthentication()为null的情况 在登录的时候,用如下方法获取输入的用户名: * 获得当前用户名称 private String getUsername() { String username = SecurityContextHolder.getContext().ge...
安卓app有一种特殊情况,就是 app运行在后台的时候,系统资源紧张的时候或者应用出现bug奔溃的时候导致把app的资源全部回收(杀死app的进程),这时把app再从后台返回到前台时,app会重启。这种情况下文简称为:“内存重启”。(屏幕旋转等配置变化也会造成当前Activity重启,本质与“内存重启”类似) 在系统要把app回收之前,系统会把Activity的状态保存下来,Activity的F
Context文直译为“上下文”,SDK对其说明如下: 1、它描述的是一个应用程序环境的信息,即上下文。 2、该类是一个抽象(abstract class)类,Android提供了该抽象类的具体实现类(后面我们会讲到是ContextIml类)。 3、通过它我们可以获取应用程序的资源和类,也包括一些应用级别操作,例如:启动一个Activity,发送广播,接受Intent信息等。 各种context及区别: 1.getApplicationContext() 返回在应用程序运行的所有活动。 最近在项目遇到一个问题,在项目Fragment的一个图标,需要在点击缩放动画完成后,跳转到另一个界面,但是经常会出现getActivity()或getContext()方法返回值为空的问题。在网上查找了很多解决方案,大概有以下几种: 1. 根据fragment的生命周期,将方法的调用写到onStart()方法内部。我将方法的调用写到了onResume()方法,都同样会
SecurityContextHolder.getContext().getAuthentication() 为null,这个问题比较难解决,很多都是什么权限问题。 springcloud ,出现这个问题一般是因为feign的熔断问题导致的。 feign.hystrix.enabled=false 立刻可以解决该问题。
做一个小项目的时候遇到了一个空指针问题, 项目的大概是这样FragmentA是一些普通布局,FragmentB是一个listview显示数据,当我从FragmentA点击 到FragmentB的时,FragmentBlistview还没有把数据加载出来时再次切换到FragmentA就会发现闪退异常空指针 然后我看了一下原因发现FragmentB里的listview适配器的Conte
Fragment回调顺序 onAttach->onCreate->onCreateView->onActivityCreated ps:最后发现经常在Fragment里面getActivity()为空,特别是在AsyncTask的onPostExecute里面,解决方案是定义Activity成员变量,然后在onAttach里面赋值 update:上面的ps可以解决空指...
&lt;script type="text/javascript"&gt;         var canvas = document.getElementById("canvas");         var can = canvas.getContext("2d");         can.fillStyle = "#990099";         can.fillRect(0, 0, 5...
Fragment使用findViewById方法,需要先获取Fragment的根视图,然后再通过根视图调用findViewById方法来查找对应的视图控件。具体步骤如下: 1. 在Fragment的onCreateView方法,通过LayoutInflater的inflate方法将布局文件转换成View对象,并返回该View对象作为Fragment的根视图。 2. 在Fragment的onViewCreated方法,通过根视图调用findViewById方法来查找对应的视图控件,并将其赋值给成员变量。 例如,在Fragment查找一个TextView控件的代码如下: public class MyFragment extends Fragment { private TextView mTextView; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_layout, container, false); return rootView; @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mTextView = view.findViewById(R.id.text_view); 在上面的代码,我们先通过LayoutInflater的inflate方法将布局文件fragment_layout转换成View对象,并将其作为Fragment的根视图返回。 然后,在onViewCreated方法,我们通过根视图view调用findViewById方法来查找id为text_view的TextView控件,并将其赋值给成员变量mTextView。这样,在Fragment的其他方法就可以直接使用mTextView来操作TextView控件了。
Cognitive Complexity of methods should not be too high Refactor this method to reduce its Cognitive 32490