Reputation: 269
I use ViewPager
and Tabs
in my application . When I test the app and move quickly between tabs
, it crashes . I have one Fragment
and 3 tabs
and the content of the Fragment
change in every tab
. The content is data from an API
using Retrofit 2
. I also use FragmentStatePagerAdapter
.
here is my Logs
.
java.lang.IllegalStateException: Fragment MainFragment{423155d0} not attached to Activity
at android.support.v4.app.Fragment.getResources(Fragment.java:715)
at com.webstore.footballscores.Fragments.MainFragment$4.onResponse(MainFragment.java:393)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:70)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5641)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1288)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1104)
at dalvik.system.NativeStart.main(Native Method)
This error in this line
res = getResources();
And the rest of code .
connection.enqueue(new Callback<List<FixturesObject>>() {
@Override
public void onResponse(Call<List<FixturesObject>> call, Response<List<FixturesObject>> response) {
if (!response.isSuccessful()) {
progressDoalog.dismiss();
Toast.makeText(getActivity(), "Something went wrong , Please refresh again", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
swipeRefreshLayout.setRefreshing(false);
}
}, 4000);
} else if (response.isSuccessful()) {
i=1;
imageView.setVisibility(View.GONE);
progressDoalog.dismiss();
if (isAdded()) {
res = getResources();
String[] teamEngList = res.getStringArray(R.array.team_english);
String[] teamArabList = res.getStringArray(R.array.team_arabic);
}
if (response.body().get(i).getLeagueId().equals("109")) {
for (int j = 0; j < teamEngList.length; j++) {
if (teamEngList[j].equals(response.body().get(i).getMatchAwayteamName())) {
response.body().get(i).setMatchAwayteamName(teamArabList[j]);
} else if (teamEngList[j].equals(response.body().get(i).getMatchHometeamName())) {
response.body().get(i).setMatchHometeamName(teamArabList[j]);
}
}
spainObject.add(response.body().get(i));
listDataChild.put(listDataHeader.get(listDataHeader.size() - 1), spainObject);
}
adapter.clearData();
adapter.addData(listDataHeader, listDataChild);
}
How can I fix this error . Thanks
Upvotes: 0
Views: 568
Reputation: 60989
You are using FragmentStatePagerAdapter
so Fragment
in ViewPager
can be destroyed then detached (see my demo here).
In each Fragment
, you run an asynchronous task (using Retrofit) and when it finished you update UI.
If you update UI for a fragment which is destroyed before, you will get the exception
There are some ways for solving your problem
Depend on your case, you can choose 1 in 3 ways
Upvotes: 1
Reputation: 4573
When you are swiping the ViewPager
is creating fragments for visible pages and destroying for those that are invisible. Your network requests are independent from that process. When a network request finishes and the corresponding fragment is destroyed, you are trying to call getResources()
but this call requires having a context. A fragment does not have a context anymore if it has been destroyed, thus, you get a crash.
To fix the issue you need to make sure that the context is available before you make that call. Try this:
if (!isAdded()) return;
res = getResources();
//...
Some documentation: https://developer.android.com/reference/android/support/v4/app/Fragment#isAdded()
Upvotes: 1
Reputation: 17755
When the request is completed the fragment has already been detached. Instead of waiting for the response then throwing it away, you could cancel() the Call, for example.
@Override
public void onDestroy() {
connection.cancel();
super.onDestroy();
}
Note that the callback will still be triggered, but with onFailure()
instead of onResponse()
Upvotes: 0