Why getContext() in fragment sometimes returns null?

后端 未结 4 2057
栀梦
栀梦 2020-12-01 12:03

Why getContext() sometimes returns null? I pass context to LastNewsRVAdapter.java as an argument. But LayoutInflater.from(contex

相关标签:
4条回答
  • 2020-12-01 12:16

    As the accepted answer says, you must look into the way you are using and caching context. Somehow you are leaking context that is causing Null Pointer Exception.


    Below Answer is as per the first revision of the question.

    Use onAttach() to get Context. Most of the cases, you don't need this solution so use this solution only if any other solution does not work. And you may create a chance to activity leak, so be cleaver while using it. You may require to make context null again when you leave from fragment

    // Declare Context variable at class level in Fragment
    private Context mContext;
    
    // Initialise it from onAttach()
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mContext = context;
    }
    

    This context will be available in onCreateView, so You should use it.


    From Fragment Documentation

    Caution: If you need a Context object within your Fragment, you can call getContext(). However, be careful to call getContext() only when the fragment is attached to an activity. When the fragment is not yet attached, or was detached during the end of its lifecycle, getContext() will return null.

    0 讨论(0)
  • 2020-12-01 12:17

    When you are sure fragment is attached to its host(onResume, onViewCreated, etc) use this instead of getContext() :

    requireContext()
    

    It will not be inspected by lint, but it will throw an Exception if context detached!

    Then you should check nullity by if clouse (or some thing) or be sure that if the program reaches this line, it isn't null.

    In retrofit calls or retrofit (and may others in the same way), it will return a disposable that must be cleared or disposed before onDestroy.

    0 讨论(0)
  • 2020-12-01 12:26

    First of all, as you can see on this link, the method onCreateView() inside the fragment's lifecycle comes after onAttach(), so you should have already a context at that point. You may wonder, why does getContext() return null then? the problem lies on where you are creating your adapter:

    App.getApiService().getLatestNews().enqueue(new Callback<LatestNews>() {
            @Override
            public void onResponse(Call<LatestNews> call, Response<LatestNews> response) {
                if (response.isSuccessful() && response.body().isSuccessfull()){
                    adapter = new LastNewsRVAdapter(getContext(), response.body().getData(), sideBanner);
                    rvLatestNews.setAdapter(adapter);
                    tvSonkuKabar.setVisibility(View.VISIBLE);
                }
            }
    
            @Override
            public void onFailure(Call<LatestNews> call, Throwable t) {
    
            }
        });
    

    Though you are specifying a callback in onCreateView(), that does not mean the code inside that callback will run at that point. It will run and create the adapter after the network call is done. With that in mind, your callback may run after that point in the lifecycle of the fragment. What I mean is that the user can enter that screen (fragment) and go to another fragment or return to the previous one before the network request finishes (and the callback runs). If that happens, then getContext() could return null if the user leaves the fragment (onDetach() may have been called).

    Besides, you can have memory leaks also, in case the activity is destroyed before your network request finishes. So you have two issues there.

    My suggestions to solve those issues are:

    1. in order to avoid the null pointer exception and the memory leak, you should cancel the network request when the onDestroyView() inside the fragment is being called (retrofit returns an object that can cancel the request: link).

    2. Another option that will prevent the null pointer exception is to move the creation of the adapter LastNewsRVAdapter outside the callback and keep a reference to it in the fragment. Then, use that reference inside the callback to update the content of the adapter: link

    0 讨论(0)
  • 2020-12-01 12:34

    So getContext() is not called in onCreateView(). It's called inside the onResponse() callback which can be invoked anytime. If it's invoked when your fragment is not attached to activity, getContext() will return null.

    The ideal solution here is to Cancel the request when the activity/fragment is not active (like user pressed back button, or minimized the app).

    Another solution is to simply ignore whatever is in onResponse() when your fragment is not attached to your activity, like this: https://stackoverflow.com/a/10941410/4747587

    0 讨论(0)
提交回复
热议问题