Android app crashing after a while using Fragments and ViewPager

10,099

Solution 1

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.

Solution 2

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;
  }
}
Share:
10,099
xteci
Author by

xteci

Updated on July 28, 2022

Comments

  • xteci
    xteci almost 2 years

    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?