lyricat
lyricat

Reputation: 1996

ViewPager onPageSelected for first page

So it appears that when using a ViewPager, the onPageSelected listener does not get called for the first page same issue as this.

I have some logic that populates some more expensive UI elements for the currently selected page and this works when page is changed, but it doesn't work for the first page.

If I set the current item after the listener, the callback gets fired for the first page, but the view has not been initialized yet, so I can't manipulate it:

// Inside PagerAdapter.instantiateItem

ViewHolder vh = new ViewHolder();
cursor.moveToPosition(position);
vh.view = adapter.newView(context, cursor, null);
// Set position as tag so we can retrieve it with findViewByTag
vh.view.setTag(position); 

((ViewPager) collection).addView(vh.view,0);       

return vh;

// Inside MyActivity.onCreate

pagerAdapter = new SingleMessagePagerAdapter(this, cursor);
pager = (ViewPager)findViewById(R.id.message_pager);
pager.setAdapter(pagerAdapter);
pager.setOnPageSelectedListener(this);
pager.setCurrentItem(selectedItem);

// Inside MyActivity.onPageSelected

// Retrieve tagged view
View view = pager.findViewWithTag(position); 

Here view ends up being null because PagerAdapter.instantiateItem has not yet been run. So I guess my question is, at which point in the activity lifecycle can I be certain that the ViewPager has initialized the view? I tried doing this inside Activity.onAttachedToWindow and Activity.onResume but it appears both of these get fired before PagerAdapter.instantiateItem.

Upvotes: 23

Views: 14306

Answers (3)

Arūnas Bedžinskas
Arūnas Bedžinskas

Reputation: 718

My solution was to extend pager adapter and create an interface inside it. Then make the adapter call the interface only once after creating the adapter. Inside interface callback you can call onPageChanged method without having nullpointerexception. Add this class to your project and extend your adapter from it. Dont forget to set listener to adapter before setting adapter to viewpager. Adapter class below:

public abstract class ExtendedPagerAdapter extends FragmentPagerAdapter {

private boolean instantiated;
private AdapterListener adapterListener;

public interface AdapterListener {
    void onAdapterInstantiated();
}

public ExtendedPagerAdapter(FragmentManager fragmentManager) {
    this(fragmentManager, null);
}

public ExtendedPagerAdapter(FragmentManager fragmentManager, AdapterListener adapterListener) {
    super(fragmentManager);
    this.adapterListener = adapterListener;
    instantiated = false;
}

@Override
public void finishUpdate(ViewGroup container) {
    super.finishUpdate(container);
    if (!instantiated) {
        instantiated = true;
        if (adapterListener != null) {
            adapterListener.onAdapterInstantiated();
        }
    }
}

public void setAdapterInstantiatedListener(AdapterListener adapterListener) {
    this.adapterListener = adapterListener;
}
}

Activity code:

adapter = new ViewPagerAdapter(getChildFragmentManager());
    adapter.setAdapterInstantiatedListener(new ExtendedPagerAdapter.AdapterListener() {
        @Override
        public void onAdapterInstantiated() {
            onPageSelected(viewPager.getCurrentItem());
        }
    });

    viewPager.addOnPageChangeListener(this);
    viewPager.setAdapter(adapter);

Upvotes: 1

SeSajad
SeSajad

Reputation: 607

try to use fragments!

public class SectionsPagerAdapter extends FragmentPagerAdapter {

    public SectionsPagerAdapter() {
        super(getSupportFragmentManager());
    }

    @Override
    public Fragment getItem(int i) {
        Fragment fr = null;
        if (i==0)
           fr = new sec0frag();
        else if (i==1)
           fr = new sec1frag();
        else if (i==2)
           fr = new sec2frag();
        return fr;
    }

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

and create 3 fragments classes

e.g. :

    public static class sec0frag extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
                     // here is initialize for first time to view pages.!
        }
    }

Upvotes: 2

brk3
brk3

Reputation: 1554

I'm wondering why you don't just have the logic you mention in the Fragment itself rather than the hosting Activity. ViewPager buffers a couple of fragments either side of the current one so they're set up in the background and ready to go when the user swipes to them. Putting the logic in onPageSelected would mean bypassing this functionality and not doing the heavy lifting until the user swipes to the page.

Assuming for some reason you can't do the above, why not use an Interface with a callback function. Trigger the callback in the fragment's onCreateView function to let the Activity know it's fully instantiated.

Upvotes: 5

Related Questions