Home » Android » crash – Android app crashing after a while using Fragments and ViewPager

crash – Android app crashing after a while using Fragments and ViewPager

Posted by: admin June 15, 2020 Leave a comment

Questions:

I’ve got a problem with my android app crashing when trying to restore my fragments. I have not added any custom variables to the bundle that I’m trying to restore, It’s all default. I’m using Fragments and ViewPager. See my code snippets below:

public static class MyAdapter extends FragmentStatePagerAdapter {
    public MyAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return NUM_ITEMS;
    }

    public int getCurrentItemPosition(Fragment fragment){
        return getItemPosition(fragment);
    }

    @Override
    public Fragment getItem(int position) {
        return ContentFragment.newInstance(position);
    }
}

public class MyActivity extends FragmentActivity {

static final int NUM_ITEMS = 100000;
public int currentSelectedPage;
private int changeToFragmentIndex;
public DateTime midDate;
MyAdapter mAdapter;
ViewPager mPager;

/** Called when the activity is first created. */
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.diary);
    MyApplication application = (MyApplication)getApplication();
    application.dataController.myActivity = this;
    mAdapter = new MyAdapter(getSupportFragmentManager());
    mPager = (ViewPager)findViewById(R.id.pager);
    mPager.setAdapter(mAdapter);
    int newDay = application.daysBetween(DateTime.now(), DateTime.parse(application.day.dateToShortString()));

    this.currentSelectedPage = NUM_ITEMS/2+newDay;
    mPager.setCurrentItem(NUM_ITEMS/2+newDay);
    mPager.setOnPageChangeListener(new SimpleOnPageChangeListener(){
        public void onPageSelected(int position){
            currentSelectedPage = position;
            ContentFragment fragment = (ContentFragment) mAdapter.instantiateItem(mPager, currentSelectedPage);
            fragment.loadData();
        }
    });
}

}

public class ContentFragment extends Fragment {
private View v;
static final int NUM_ITEMS = 100000;

static ContentFragment newInstance(int num) {
    ContentFragment f = new ContentFragment();

    return f;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    if (container == null)
        return null;
    v = inflater.inflate(R.layout.diarycontent, container, false);
    return v;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

}

@Override
public void onSaveInstanceState(Bundle savedInstanceState){
    super.onSaveInstanceState(savedInstanceState);
    setUserVisibleHint(true);
}
}

I receive this stackstrace:

Caused by: java.lang.NullPointerException
at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:519)
at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:1 55)
at android.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:522)

As I have understood this may be a known problem with the support package and that one possible solution would be to use setUserVisibleHint(true) in onSaveInstanceState. But that didn’t help.

Does anyone know another solution to the problem or what I’ve done wrong?

How to&Answers:

I have faced same type of issue once I started using ViewPager with FragmentStatePagerAdapter inside Tab.

Then I played with all forums related to this issue and break my head for two days to find out why this issue is occurred and how to resolve it but does not found any perfect solution that fulfills as per my requirement.

I got the solution as in order to avoid the NPE crash use FragmentPagerAdapter instead of FragmentStatePagerAdapter. When I replace FragmentPagerAdapter instead of FragmentStatePagerAdapter then not faced NPE crash issue but the same page is not refreshed itself for further navigation(which is my requirement).

Finally override the saveState method on FragmentStatePagerAdapter and everything working fine as expected.

@Override
public Parcelable saveState() {
    // Do Nothing
    return null;
}



How I reproduce this issue easily :

I am using the higher version(4.1) device and followed the below steps:

1. Go to Settings -> Developer Options.

2. Click the option “Do not keep activities”.

Now I played with my app.

Before override the saveState() method each time the app is crashing due to the NPE at android.support.v4.app.FragmentManagerImpl.getFragment(Unknown Source). But after override saveState() no crash is registered.

I hope by doing so you will not having any issue.

Answer:

I initially used solution suggested by @Lalit Kumar Sahoo. However, I noticed a serious issue: every time I rotated the device, the Fragment Manager added new fragments without removing the old ones. So I searched further and I found a bug report with a workaround suggestion (post #1). I used this fix and tested with my app, the issue appears to be resolved without any side-effects:

Workaround: Create custom FragmentStatePagerAdapter in project’s src/android/support/v4/app folder and use it.

package android.support.v4.app;

import android.os.Bundle;
import android.view.ViewGroup;

public abstract class FixedFragmentStatePagerAdapter extends FragmentStatePagerAdapter {

  public FixedFragmentStatePagerAdapter(FragmentManager fm) {
    super(fm);
  }

  @Override
  public Object instantiateItem(ViewGroup container, int position) {
    Fragment f = (Fragment)super.instantiateItem(container, position);
    Bundle savedFragmentState = f.mSavedFragmentState;
    if (savedFragmentState != null) {
      savedFragmentState.setClassLoader(f.getClass().getClassLoader());
    }
    return f;
  }
}

Answer:

Why exactly are you doing:

mPager.setOnPageChangeListener(new SimpleOnPageChangeListener(){
    public void onPageSelected(int position){
        currentSelectedPage = position;
        ContentFragment fragment = (ContentFragment) mAdapter.instantiateItem(mPager, currentSelectedPage);
        fragment.loadData();
    }
});

This:

@Override
public Fragment getItem(int position) {
    return ContentFragment.newInstance(position);
}

Instantiates the fragment.

You can load data like this in the fragment :

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
loadData();
}