Shawn Mercado
Shawn Mercado

Reputation: 132

onPageSelected runs BEFORE onCreateView is called?

I'm using a ViewPager to cycle through a set of fragments, and I want to update each fragment after it slides onto the screen. Basically, I want the text to "fade in" after the fragment has settled.

I tried using the fragment's onStart and onResume methods, and while this works for most of the pages, it does NOT work for the second page, because for whatever dumb reason, the first page AND the second page have their onStart/onResume methods called at the same time (before the second page ever hits the screen).

Now I'm trying to get it to work with the onPageChangeListener's onPageSelected callback. That method looks like this:

@Override
public void onPageSelected(final int position) {
    mCurrentPosition = position;

    PageFragment fragment = (PageFragment) ((MainActivity.ScreenSlidePagerAdapter) mViewPager.getAdapter()).getItem(position);

    fragment.onSelect();

}

And the onSelect method in the fragment looks like this:

public void onSelect(){

    new android.os.Handler().postDelayed(
            new Runnable() {
                public void run() {

                    mSwitcher.setText("");

                    mNum = getArguments() != null ? getArguments().getInt("num") : 1;
                    Media currentMedia = slideshow.getMedia().get(mNum);

                    mSwitcher.setText(currentMedia.getDisplayName());
                }
            },
            4000);
}

The problem with this way is that the line mSwitcher.setText(""); throws a NullPointerException

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextSwitcher.setText(java.lang.CharSequence)' on a null object reference

Which would suggest that the onCreateView method in that class has yet to run since that's where the mSwitcher variable is instantiated. Which seems bananas to me, since the view is already sliding onto the screen at this point.

Any ideas about how to solve this problem would be greatly appreciated. This is my first Android experience, and I've been trying to solve this stupid text-fade-in issue for a full week with no luck. At this point I'm almost ready to abandon mobile as a platform because of how painful every minor change has been so far.

Upvotes: 3

Views: 1662

Answers (2)

aaronhigh
aaronhigh

Reputation: 91

I have the similar problem as yours, onPageSelected() is called before the fragments are initialized, but your description is not detailed enough, such as how you select the second page.

When adapter is fed with Fragments, or we say getCount() > 0, getItem() will whatever returns a Fragment, which is not null. But this doesn't mean it is initialized, at least it doesn't if you extend from FragmentStatePagerAdapter.

when adapter is fed with data and called notifyDataSetChange(), adapter will initialize the first two pages by default. If you call setCurrentItem() to move to other pages immediately after notifyDataSetChange() the issue might happen. During the runtime, setCurrentItem() -> onPageSelected() might be called before the fragments are initialized.

my solution is using view.post() when setCurrentItem(). e.g.

viewPager.post(() -> viewPager.setCurrentItem(index));

Upvotes: 2

Sandip Fichadiya
Sandip Fichadiya

Reputation: 3480

ViewPager keeps the next page in memory & this is it's default behaviour. You could adjust it by calling like:

viewPager.setOffscreenPageLimit(2);

However this might not be useful as if you pass 0 in above method, viewPager will ignore it.

You are going in right direction. I believe now problem is in your ScreenSlidePagerAdapter. In getItem(int position) you might have something like

if(position == 1)
    return new PageFragment();

instead change the adapter to something like following,

public class ScreenSlidePagerAdapter extends FragmentPagerAdapter {

    private List<Fragment> mFragments = new ArrayList<>();

    public ScreenSlidePagerAdapter(FragmentManager fm, List<Item> items) {
        super(fm);

        for (Item item : items) {
            mFragments.add(new PageFragment());
        }
    }


    @Override
    public int getCount() {
        return mFragments.size();
    }

    @Override
    public Fragment getItem(int position) {
        return mFragments.get(position); // Return from list instead of new PagerFragment()
    }
}

Upvotes: 2

Related Questions