Reputation: 132
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
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
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