Let's Learnit Let's Learnit - 1 month ago 14
Android Question

Fragment is getting detached sometimes while switching

I am working with retrofit for retrieving data from server in fragments. But the app sometimes gets crashed with the following error in logcat:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.support.v4.app.FragmentActivity.getApplicationContext()' on a null object reference
at com.adarsh.quoteit.fragment.Frnd$1.onResponse(Frnd.java:60)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:66)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5692)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754)


This is class for fragment..every fragment is working on same concept and same error comes in any fragment due to which the app is crashed.
My fragment class is as follows:

public class Motive extends Fragment {

private RecyclerView motiveRecycler;
private QuoteAdapter motiveAdapter;
private List<QuoteList> qItems;

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View motive_view = inflater.inflate(R.layout.fragment_motivation, container, false);
motiveRecycler = (RecyclerView) motive_view.findViewById(R.id.rv_motiv);
motiveRecycler.setLayoutManager(new LinearLayoutManager(getActivity()));
loadJSON();
return motive_view;
}

private void loadJSON() {
qItems = new ArrayList<>();
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://velapanti.esy.es")
.addConverterFactory(GsonConverterFactory.create())
.build();
MotiveApi requestInterface = retrofit.create(MotiveApi.class);
Call<List<QuoteList>> call = requestInterface.getJSON();
call.enqueue(new Callback<List<QuoteList>>() {
@Override
public void onResponse(Call<List<QuoteList>> call, Response<List<QuoteList>> response) {
qItems = response.body();
/*if(!isAdded()) {
Fragment
}*/
motiveAdapter = new QuoteAdapter(getActivity().getApplicationContext(), qItems);
motiveRecycler.setAdapter(motiveAdapter);

}

@Override
public void onFailure(Call<List<QuoteList>> call, Throwable t) {

}
});
}
}

Ben Ben
Answer

When doing any threaded work with fragments you should always check if the fragment is added before doing any work with the response. If the network connection is slow the fragment could be closed if the user changed the screen and the call hasn't returned.

You just need to wrap your commented out if statement around your adapter updates.

if(isAdded()) {
     motiveAdapter = new QuoteAdapter(getActivity().getApplicationContext(), qItems);
     motiveRecycler.setAdapter(motiveAdapter);       
}

Also as a general rule doing your network operations in a view fragment might not be the best idea. You could look into loaders which handle lifecycle changes for you, or using retained fragments.

Comments