erik
erik

Reputation: 4948

Fragment ViewPager NullPointer issue

I have some fragments being swapped in and out of my main activity. The initial fragment is called BrowseHomeFragment and loads fine initially, but when I replace it with a new fragment and then replace it back I get the following error

java.lang.NullPointerException: Attempt to invoke virtual method 'int java.util.ArrayList.size()' on a null object reference
    at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:686)
    at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:215)
    at android.support.v4.view.ViewPager.setAdapter(ViewPager.java:536)

onCreateView Method of BrowseHomeFragment:

public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
        InjectionGraph.inject(this);

        View view = inflater.inflate(R.layout.fragment_browse, container, false);
        ButterKnife.inject(this, view);

        addTabsToPagerSlidingTabStrip(inflater);

        viewPager.setAdapter(new BrowseHomePagerAdapter(getChildFragmentManager()));

        pagerSlidingTabStrip.setViewPager(viewPager);
        // has to set page change listener in indicator
        pagerSlidingTabStrip.setOnPageChangeListener(pageChangeListener);

        viewPager.setCurrentItem(initialTabIndex);

        return view;
    }

BrowseHomePagerAdapter

public class BrowseHomePagerAdapter extends FragmentStatePagerAdapter {
    private int lastPosition = -1;

    @Inject
    BrowseHomepageMetricRecorder browseHomepageMetricRecorder;

    @Inject
    NetworkMonitor networkMonitor;


    /**
     * For explanation on why Fragment references are cached, please refer to
     * http://stackoverflow.com/questions/8785221/retrieve-a-fragment-from-a-viewpager
     */
    final SparseArray<Fragment> registeredFragments = new SparseArray<>();


    public BrowseHomePagerAdapter(FragmentManager fm) {
        super(fm);
        InjectionGraph.inject(this);

    }


    @Override
    public Fragment getItem(int i) {

        switch (BrowseHomeFragment.Tab.resolve(i)) {
        // TODO: connect category, favorite, and downloaded list fragments
        case Categories:
            return new CategoryHomePageFragment();
        case Downloaded:
            return new OfflineContentFragment();
        default:
            return new ComingSoonFragment();
        }
    }


    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }


    @Override
    public int getCount() {
        return BrowseHomeFragment.Tab.values().length;
    }


    @Override
    public CharSequence getPageTitle(int position) {
        return BrowseHomeFragment.Tab.resolve(position).name();
    }


    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        if (position != lastPosition) { // debounce Android's redundant calls
            switch (BrowseHomeFragment.Tab.resolve(position)) {
                case Categories:
                    browseHomepageMetricRecorder.recordGotoCategoriesMetric();
                    if (!networkMonitor.isDeviceConnected()) {
                        networkMonitor.postUserActionRequiresConnectivityEvent();
                    }
                    break;
                case Downloaded:
                    browseHomepageMetricRecorder.recordGotoDownloadedMetric();
                    break;
                default:
                    break;
            }
            lastPosition = position;
        }

        super.setPrimaryItem(container, position, object);
    }


    public Object instantiateItem(ViewGroup container, int position) {
        final Fragment fragment = (Fragment) super.instantiateItem(container, position);
        registeredFragments.put(position, fragment);
        return fragment;
    }


    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        registeredFragments.remove(position);
        super.destroyItem(container, position, object);
    }


    public Fragment getRegisteredFragment(int position) {
        return registeredFragments.get(position);
    }

I gather that the viewPager is loosing something though I have run debug and its not null..

I can fix this by simply recreating my BrowseFragment each time before I replace the active fragment with it, but I'd rather just be able to reuse it.

Any help understanding what exactly is happening and how to resolve it would be greatly appreciated.

Upvotes: 1

Views: 1078

Answers (1)

erik
erik

Reputation: 4948

After banging my head, I have found a solution.. In my adapter I am now overriding the onRestoreState to do nothing..

@Override
public void restoreState(Parcelable state, ClassLoader loader) {
     //Do NOTHING;
}

I am not sure if this is the best solution, doesn't seem to have any bad effects, and if someone could speak to this "fix" and why it works or offer a better solution it would be greatly appreciated.

Upvotes: 5

Related Questions