2

My Context

Assume i have a Fragment contain a ViewPager which have 3 pages(fragment). My onCreateView method:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.main_tv_fragment, null);
        listFragment = new ArrayList<>();
        listFragment.add(new EventFragment());
        listFragment.add(new ChannelFragment());
        listFragment.add(new FavoriteFragment());
        viewPager = (ViewPager) rootView.findViewById(R.id.viewpager);
        fragmentPagerAdapter = new MainLiveTVtAdapter(
                getChildFragmentManager(), listFragment);

        slidingTabLayout = (SlidingTabLayout) rootView.findViewById(R.id.sliding_tabs);
        // Center the tabs in the layout
        slidingTabLayout.setDistributeEvenly(true);
        slidingTabLayout.setCustomTabColorizer(null);
        try {
            viewPager.setAdapter(fragmentPagerAdapter);
        } catch (Exception ex) {
            ex.getMessage();
        }
        slidingTabLayout.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
            @Override
            public int getIndicatorColor(int position) {
                return getActivity().getResources().getColor(R.color.action_bar_bg);
            }
        });
        slidingTabLayout.setViewPager(viewPager);
        viewPager.setOffscreenPageLimit(5);
        viewPager.setAdapter(fragmentPagerAdapter);
        slidingTabLayout.setViewPager(viewPager);
        viewPager.setCurrentItem(page, false);
        return rootView;
    }

I called viewPager.setCurrentItem(page, false); to set the current page of ViewPager, assume page = 1 mean the second page. When fragment is rendered in window, the second page is shown up, i scroll ViewPager to third page then replace this fragment by another one. After that i recreate this fragment and bring it on, but the ViewPager still shown the third page even viewPager.setCurrentItem(page, false); was called with page = 1.

As you can see above, ViewPager have been created new instance and the Adapter is also.

Can anyone explain why it happen? And how can i fix it?

EDIT

There is my Adapter for ViewPager

public class MainLiveTVtAdapter extends FragmentStatePagerAdapter {
    private List<Fragment> fragments;
    private String[] title = {"Sự kiện", "Kênh","Yêu thích"};
    FragmentManager fm;
    public MainLiveTVtAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);
        this.fm=fm;
        this.fragments = fragments;
    }

    @Override

    public Fragment getItem(int position) {
        return this.fragments.get(position);
    }

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

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

    @Override
    public CharSequence getPageTitle(int position) {
        return title[position];
    }

//    @Override
//    public void destroyItem(ViewGroup container, int position, Object object) {
//        if (position >= getCount()) fm.beginTransaction().remove((Fragment) object).commit();
//    }
}
mr.icetea
  • 2,607
  • 3
  • 24
  • 42
  • can you please add the code for `MainLiveTVtAdapter` – royB Mar 29 '15 at 21:41
  • @mr.icetea what do you mean by doesn't preserve it's state? – Hades Mar 30 '15 at 02:13
  • Check out : http://www.truiton.com/2013/05/android-fragmentstatepageradapter-example/ – Haresh Chhelana Mar 30 '15 at 07:13
  • 1
    Try to create instance of each fragment in getItem() base on position instead of getting from list. – Haresh Chhelana Mar 30 '15 at 07:16
  • This: `viewPager.setOffscreenPageLimit(5);` is why the ViewPager is retaining the instances. The [doc](http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit(int)) says: > Set the number of pages that should be retained to either side of the > current page in the view hierarchy in an idle state. Pages beyond this > limit will be recreated from the adapter when needed. – Ugo Dec 07 '15 at 10:20

3 Answers3

1

This is how platform is designed. It tries to keep state of views which have ids when activity/fragment is recreated. ViewPager's position is kept the same way EditText's content is. If you want to get rid of this - there are few ways:

  • override onSaveInstanceState and call viewPager.setCurrentItem() with index of your choice,
  • override onSaveInstanceState and call viewPager.setAdapter(null),
  • override onRestoreInstanceState and call viewPager.setCurrentItem() with index of your choice

There are probably other ways too but usually devs are fine with default behavior which preserves state.

Please note that current item will be the one you set in onCreate if fragment/activity is freshly added and not recreated (savedInstanceState equal to null).

questioner
  • 2,283
  • 3
  • 26
  • 35
  • `onSaveInstanceState ` was not called when i replaced it with another fragment. And there is no `onRestoreInstanceState ` in a fragment :( – mr.icetea Mar 30 '15 at 01:39
  • I found `onDestroyView` method which was called when fragments replaced. I put `viewPager.setCurrentItem()` inside this method and before `super call` but it still didn't work. – mr.icetea Mar 30 '15 at 01:54
  • In `onCreateView `add: `setRetainInstance(false);` and instead of `onRestoreInstanceState` use: `onActivityCreated()` – questioner Mar 30 '15 at 08:56
1

If you want to do any dynamic stuff with your pageradapter, you have to implement it like this: Retrieve a Fragment from a ViewPager Otherwise it will behave strangely.

Community
  • 1
  • 1
einschnaehkeee
  • 1,858
  • 2
  • 17
  • 20
0

This: viewPager.setOffscreenPageLimit(5); is why the ViewPager is retaining the instances. The doc says:

Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state. Pages beyond this limit will be recreated from the adapter when needed.

Ugo
  • 587
  • 8
  • 12