8

I'm trying to build an app that shows a book in portrait and landscape mode. So obviously there's 1 page showed in portrait and 2 in landscape. Each of the mode works pretty good but when i change the orientation from portrait to landscape the viewPager try to get 2 pages from the portrait mode instead of trying to get 2 double pages from the landscape mode ... In fact FragmentStatePagerAdapter keeps The 2 fragments created in portrait and uses them before creating 2 double page for the landscape mode. If i switch again in portrait mode, FragmentStatePagerAdapter uses the 2 fragments previously created in landscape mode so i see again 1 double page instead of 1 single page etc.. if i continue switching orientation, i get an OutOfMemoryError due to the fact that FragmentStatePagerAdapter never flush it's fragments on orientation change.

Here's 2 use cases for easier understanding :

  • i launch viewPager in portrait mode
  • i see page 1 ok
  • i swipe to right and i see page 2 ok
  • i swipe to right and i see page 3 ok
  • i rotate the screen to landscape mode
  • i see page 3 wrong
  • i swipe to right and i see page 4 wrong
  • i swipe to right and i see page 5 and 6 ok

  • i launch viewPager in portrait mode

  • i see page 1 ok
  • i swipe to right and i see page 2 ok
  • i swipe to right and i see page 3 ok
  • i swipe to right and i see page 4 ok
  • i swipe to right and i see page 5 ok
  • i rotate the screen to landscape mode
  • i see page 5 wrong
  • i swipe to left and i see page 4 wrong
  • i swipe to left and i see page 2 and 3 ok

    public class PlayerFragmentActivity extends FragmentActivity {
    private Intent mIntent;
    private ViewPager mPortraitPager;
    private ViewPager mLandscapePager;
    private Boolean mIsLandscape;
    private String mKey;
    private int mNbPages;
    private int mNbDoublePages;
    private PageFactory mPageFactory;
    private DoublePageFactory mDoublePageFactory;
    private PagerAdapter mPagerAdapter;
    
    @Override
    protected void onStop(){
        super.onStop();
        mPagerAdapter = null;
        mDoublePageFactory = null;
        mPageFactory = null; 
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_activity_player);
        mIntent = getIntent();
        mKey = mIntent.getStringExtra("key");
        mNbPages = mIntent.getIntExtra("nbPages", 0);
        mNbDoublePages = DoublePageFactory.getDoublePageNumFromPageNum(mNbPages);
    
        Resources res = getResources();
        mIsLandscape = (res.getConfiguration().orientation == 1) ? false : true;
        mPortraitPager = (ViewPager) findViewById(R.id.portraitPager);
        mLandscapePager = (ViewPager) findViewById(R.id.landscapePager);
    
        mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
    
        if (mIsLandscape) {
            mDoublePageFactory = new DoublePageFactory(this, mKey, mNbPages, res.getInteger(R.integer.nb_page_columns), res.getInteger(R.integer.nb_page_columns));
            mPortraitPager.setVisibility(View.GONE);
            mLandscapePager.setAdapter(mPagerAdapter);
            mPortraitPager.setAdapter(null);
        } else {
            mPageFactory = new PageFactory(this, mKey, this.mNbPages, res.getInteger(R.integer.nb_page_columns), res.getInteger(R.integer.nb_page_columns));
            mLandscapePager.setVisibility(View.GONE);
            mPortraitPager.setAdapter(mPagerAdapter);
            mLandscapePager.setAdapter(null);
        }
    }
    
    
    public class MyPagerAdapter extends FragmentStatePagerAdapter {
    
        public MyPagerAdapter(FragmentManager fm) {
            super(fm);
        }
    
        @Override
        public Fragment getItem(int position) {
            Bundle args = new Bundle();
            if(mIsLandscape){
                Fragment doublePageFragment = new DoublePageFragment();
                args.putInt(DoublePageFragment.ARG_DOUBLEPAGE_NUM, position + 1);
                doublePageFragment.setArguments(args);
                return doublePageFragment;
            }else{
                Fragment pageFragment = new PageFragment();
                args.putInt(PageFragment.ARG_PAGE_NUM, position + 1);
                pageFragment.setArguments(args);
                return pageFragment;
            }
        }
    
        @Override
        public int getCount() {
            return (mIsLandscape) ? mNbDoublePages:mNbPages;
    
        }
    
                /* j'ai essayé cette méthode mais ça ne fonctionne pas :( */
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
                FragmentManager manager = ((Fragment) object).getFragmentManager();
                FragmentTransaction trans = manager.beginTransaction();
                trans.remove((Fragment) object);
                trans.commit();
    
            super.destroyItem(container, position, object);
        }
    
        @Override
        public int getItemPosition(Object object){
            return PagerAdapter.POSITION_NONE;
        }
    
        @Override
        public CharSequence getPageTitle(int position) {
            return "p." + position + 1;
        }
    }
    
    public boolean isLandscape() {
        return mIsLandscape;
    }
    
    public ImageView getSinglePage(int position) {
        return mPageFactory.getPage(position);
    }
    
    
    public LinearLayout getDoublePage(int position) {
        return mDoublePageFactory.getDoublePage(position);
    }
    }
    
    
    public class PageFragment extends Fragment {    
    private PlayerFragmentActivity mPlayerFragmentActivity;
    public static final String ARG_PAGE_NUM = "page_number";
    public static final String ARG_WOBOOK_DIRECTORY = "book_directory";
    public static final String ARG_NB_PAGE_COLUMNS = "nb_page_columns";
    public static final String ARG_NB_PAGE_ROWS = "nb_page_rows";
    
    @Override
    public ImageView onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        mPlayerFragmentActivity = ((PlayerFragmentActivity) getActivity());
        return mPlayerFragmentActivity.getSinglePage(getArguments().getInt(ARG_PAGE_NUM));
    }
    
    @Override
    public void onStop(){
        super.onStop();
        mPlayerFragmentActivity = null;
    }
    

    }

    public class DoublePageFragment extends Fragment {
    private PlayerFragmentActivity mPlayerFragmentActivity;
    public static final String ARG_DOUBLEPAGE_NUM = "double_page_number";
    public static final String ARG_WOBOOK_DIRECTORY = "book_directory";
    public static final String ARG_NB_PAGE_COLUMNS = "nb_page_columns";
    public static final String ARG_NB_PAGE_ROWS = "nb_page_rows";
    
    @Override
    public LinearLayout onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        mPlayerFragmentActivity = ((PlayerFragmentActivity) getActivity());
        return mPlayerFragmentActivity.getDoublePage(getArguments().getInt(ARG_DOUBLEPAGE_NUM));
    }
    
    @Override
    public void onStop(){
        super.onStop();
        mPlayerFragmentActivity = null;
    }
    }
    

i've read that the FragmentManager in the framework takes care of saving the state and restore any active fragments that the pager has made. So i guess that when the orientation changes, the FragmentManager says

Hey ! I already have 2 items created so i don't need to create news, lets get them

But in fact it gets the 2 items (page/double page) from the old orientation mode. So i need to fnd a way to delete the fragments saved by the FragmentManager when the orientation change occurs.

I've also tested this method. The problem seems to be related to this one

Best regards

Community
  • 1
  • 1
Big_Boulard
  • 799
  • 1
  • 13
  • 28

1 Answers1

-1

Try to limit orientation to either portrait or Landscape mode.Because we can use view pager only in exact mode.

Lucky Rana
  • 1,030
  • 1
  • 12
  • 20