I have a fragment (F1) with a public method like this
public void asd() {
if (getActivity() == null) {
Log.d(\"yes\",\"it is null\");
}
}
For the first part @thucnguyen was on the right track.
This happened when you call getActivity() in another thread that finished after the fragment has been removed. The typical case is calling getActivity() (ex. for a Toast) when an HTTP request finished (in onResponse for example).
Some HTTP calls were being executed even after the activity had been closed (because it can take a while for an HTTP request to be completed). I then, through the HttpCallback
tried to update some Fragment fields and got a null
exception when trying to getActivity()
.
http.newCall(request).enqueue(new Callback(...
onResponse(Call call, Response response) {
...
getActivity().runOnUiThread(...) // <-- getActivity() was null when it had been destroyed already
IMO the solution is to prevent callbacks to occur when the fragment is no longer alive anymore (and that's not just with Okhttp).
If you have a look at the fragment lifecycle (more info here), you'll notice that there's onAttach(Context context)
and onDetach()
methods. These get called after the Fragment belongs to an activity and just before stop being so respectively.
That means that we can prevent that callback to happen by controlling it in the onDetach
method.
@Override
public void onAttach(Context context) {
super.onAttach(context);
// Initialize HTTP we're going to use later.
http = new OkHttpClient.Builder().build();
}
@Override
public void onDetach() {
super.onDetach();
// We don't want to receive any more information about the current HTTP calls after this point.
// With Okhttp we can simply cancel the on-going ones (credits to https://github.com/square/okhttp/issues/2205#issuecomment-169363942).
for (Call call : http.dispatcher().queuedCalls()) {
call.cancel();
}
for (Call call : http.dispatcher().runningCalls()) {
call.cancel();
}
}