Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ViewPager Fragment being called twice

Ok, so I'm trying to implement a ViewPager with three pages, and to have unique content on each one, so I've set up a system where I am inflating different layouts based off of the page index. This is working as soon as i navigate, but I'm noticing that the Fragment is being called twice.

Here's my FragmentAcivity class:

public class TutorialScreen extends FragmentActivity {

    private static final String TAG = "TAG";
    private static final int NUM_PAGES = 3;
    private ViewPager pager; // animation handler
    private PagerAdapter adapter; // provides pages to pager

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.tutorial_layout);

        // Instantiate Pager & Adapter
        pager = (ViewPager) findViewById(R.id.pager);
        adapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
        pager.setAdapter(adapter);
        Log.v(TAG, "Initial Page is " + pager.getCurrentItem()); // this logs '0' - which is what i want
        pager.setCurrentItem(pager.getCurrentItem());
    }

    @Override
    public void onBackPressed() {
        if(pager.getCurrentItem() == 0) {
            super.onBackPressed();
        }
        else {
            pager.setCurrentItem(pager.getCurrentItem() -1);
        }
    }

    // Pager Adapter SubClass
    private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {

        public ScreenSlidePagerAdapter(FragmentManager fm) {
            super(fm);
            Log.v(TAG, "constructor"); // this logs once
            pager.setCurrentItem(pager.getCurrentItem());
        }

        @Override
        public Fragment getItem(int position) {
            Log.v(TAG, "getItem " + position); // this logs twice
            return new ScreenSlidePageFragment(position); // note I've overridden the constructor
        }

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

and my Fragment class:

public class ScreenSlidePageFragment extends Fragment {

    private static int pageIndex;
    private static final String TAG = "TAG";

    ScreenSlidePageFragment(int id) {
        pageIndex = id;
        Log.v(TAG, "Page Index is " + pageIndex); // this logs twice
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        int resID = -1;

        switch(pageIndex) {
            case 0:
                resID = R.layout.tutorial_page1;
                break;
            case 1:
                resID = R.layout.tutorial_page2;
                break;
            case 2:
                resID = R.layout.tutorial_page3;
                break;
            default:
                resID = R.layout.tutorial_page1;
                break;
        }

        Log.v(TAG, "Res Index is " + resID); // this logs twice
        ViewGroup rootView = (ViewGroup) inflater.inflate(resID, container, false);
        return rootView;
    }
}

The Log is

constructor getItem 0 Page Index is 0 getItem 1 Page Index is 1 Res Index is 2130903043 Res Index is 2130903043

So basically it is jumping to the second page right away, regardless of whether I set the position with setCurrentItem() ...

I think that I may be cheating by trying to only have one Fragment class, instead of a separate one for each matching layout, but... this should work ?

Note that I am seeing a (I think) related issue in that the second (initial) page is showing up twice - once initially, and then after swiping to the next page again (which should be page 3?). Once I navigate to Page 3 (after two swipes) I can go all the way back to Page 1 (which should be the initial page).

Thoughts? What am I doing wrong ?

like image 526
jesses.co.tt Avatar asked Oct 20 '22 08:10

jesses.co.tt


1 Answers

So, I solved my own (root) issue (though not the weird index-case that i was experiencing).

My misconception around the instantiation of individual content for each page in the ViewPager was that there would be a single Fragment used over and over, and I would pass arguments to it's constructor in order to tell it which layout to inflate.

Instead, I realized that I should have wholly separate Fragment classes, each owning it's own unique layout, and I could use the same position id from getItem() in the FragmentStatePagerAdapter to instantiate the correct Fragment... makes sense to me now.

See code below:

public class TutorialScreen extends FragmentActivity {

    private static final int NUM_PAGES = 3;
    private ViewPager pager; 
    private PagerAdapter adapter; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.tutorial_layout);

        // Instantiate Pager & Adapter
        pager = (ViewPager) findViewById(R.id.pager);
        adapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
        pager.setAdapter(adapter);
    }

    @Override
    public void onBackPressed() {
        if(pager.getCurrentItem() == 0) {
            super.onBackPressed();
        }
        else {
            pager.setCurrentItem(pager.getCurrentItem() -1);
        }
    }

    // PagerAdapter SubClass
    private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {

        public ScreenSlidePagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            Fragment fragment;
            switch(position) {
                case 0:
                    fragment = new TutorialPage1();
                break;
                case 1:
                    fragment = new TutorialPage2();
                break;
                case 2:
                    fragment = new TutorialPage3();
                break;
                default:
                    fragment = new TutorialPage1();
                break;
            }
            return fragment;
        }

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

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

    } /* EOC */

} /* EOC */ 
like image 118
jesses.co.tt Avatar answered Oct 23 '22 01:10

jesses.co.tt