Why getContext() in fragment sometimes returns null?
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:
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).
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
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 yourFragment
, you can callgetContext()
. However, be careful to callgetContext()
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 returnnull
.
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