38

Currently, with a FragmentActivity, I toggle among 2 type of Fragments using the following code.

private void toggle() {
    Fragment oldFragment = getSupportFragmentManager().findFragmentById(R.id.content);
    Fragment fragment = null;
    if (oldFragment instanceof ColorFragment) {
        fragment = new ViewPagerFragment();
    } else {
        fragment = new ColorFragment(android.R.color.black);
    }

    getSupportFragmentManager().beginTransaction().replace(R.id.content, fragment).commitAllowingStateLoss();
}

2 Fragments are being toggle.

  • ColorFragment - A simple fragment which fill up its background with solid black color.
  • ViewPagerFragment - A fragment contains ViewPager. User can swipe between a purple color fragment, and a blue color fragment.

The code which responsible for swiping purple and blue color fragments are as below.

private static class MyFragmentPagerAdapter extends FragmentPagerAdapter {

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

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

    @Override
    public Fragment getItem(int position) {
        switch (position) {
        case 0:
            return new ColorFragment(android.R.color.holo_purple);
        default:
            return new ColorFragment(android.R.color.holo_blue_bright);
        }
    }      
} 

However, I encounter the weird behavior during toggling.

  1. Black color fragment was shown.
  2. Toggling.
  3. View pager, which can swipe between purple and blue fragments shown.
  4. Toggling.
  5. Black color fragment was shown.
  6. Toggling.
  7. Nothing shown, as MyFragmentPagerAdapter's getItem is not being triggered.

I think my situation is similar to FragmentPagerAdapter getItem is not called

However, I prefer not to use FragmentStatePagerAdapter, because of the cost of potentially more overhead when switching between pages.

Any workaround to overcome this problem?

I include a complete workable source code to demonstrate this problem : https://www.dropbox.com/s/jok9tz5ktvfcteo/viewpagerbug.zip

Community
  • 1
  • 1
Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875
  • *I prefer not to use FragmentStatePagerAdapter* - well, did you at least tried it to see if it makes any differences? *because of the cost of potentially more overhead when switching between pages.* - what potentially overhead? the scenario you posted with two fragments is dead simple. – user Mar 23 '13 at 14:59
  • @Luksprog The 2 purple and blue color fragments are for demonstration purpose. The real cases fragments are more complicated than that. I know I can reduce certain extend of overhead, by saving the information through bundle, or retained instance fragment technique. however, i realize the best way to avoid overhead for my case, is to avoid using FragmentStatePagerAdapter. – Cheok Yan Cheng Mar 23 '13 at 15:30

5 Answers5

113

Any workaround to overcome this problem?

I've downloaded your code and the problem appears because you don't handle those Fragments right. Most precisely you use nested Fragments in the ViewPager based Fragment and for that ViewPager you create the adapter like this:

MyFragmentPagerAdapter myFragmentPagerAdapter = new MyFragmentPagerAdapter(this.getFragmentManager());

Instead, you should be using getChildFragmentManager() to bind the nested fragments:

MyFragmentPagerAdapter myFragmentPagerAdapter = new MyFragmentPagerAdapter(this.getChildFragmentManager());

Also, you shouldn't pass data through a constructor to a Fragment as that data will not survive a configuration change and bad things will start to appear. Use a Bundle instead.

user
  • 86,916
  • 18
  • 197
  • 190
  • 1
    Hey. Really thanks for big help. However, I do not understand why using this.getChildFragmentManager will solve the problem. As from http://developer.android.com/reference/android/support/v4/app/FragmentPagerAdapter.html, it is using FragmentActivity's fragment manager through getSupportFragmentManager() (FragmentActivity is the owner of ViewPager). It does not use ArrayListFragment's fragment manager (ArrayListFragment(s) are the swipable contents of ViewPager) – Cheok Yan Cheng Mar 23 '13 at 16:26
  • In this.getChildFragmentManager(), it is returning the fragment manager for purple and blue fragments. This is different from the official example, which is using ViewPager's owner's fragment manager. Hence, this confuses me some how. – Cheok Yan Cheng Mar 23 '13 at 16:28
  • 1
    I'm not sure whether this really answers my own question. I think the example given is fragment within activity. Using getFragmentManager makes sense. However, if for nested fragment within fragment, using getChildFragmentManager is needed. This is some how a "rule" posted by Google : http://developer.android.com/about/versions/android-4.2.html#NestedFragments – Cheok Yan Cheng Mar 23 '13 at 16:48
  • 12
    @CheokYanCheng `getFragmentManager()` in your `ViewPagerFragment` example will return the `FragmentManager` from the `Activity`(it's basically the value of `getSupportFragmentmanager()` in the `FragmentActivity` used to add the `Fragment`). As you use nested fragments those require the `getChildFragmentManager()` so they can be attached to the parent fragment. `getFragmentManager()` and `getChildFragmentManager` **aren't** the same thing in a `Fragment`(one returns the fragment related to the fragment and the other is the fragmentmanager used for its nested fragments). – user Mar 23 '13 at 16:51
  • 2
    If I could +1 more then once I would! Thanks so much for both the answer and the explanation! – Matthew Clark Apr 16 '14 at 23:37
  • works perfectly! i've had the same problem using a FragmentStatePagerAdapter. – dy_ Sep 18 '14 at 15:54
  • getChildFragmentManager doesn't exist in the support packages though? – Oliver Dixon Feb 04 '16 at 07:29
  • @iLoveUnicorns getChildFragmentManager is available for support fragments: http://developer.android.com/reference/android/support/v4/app/Fragment.html#getChildFragmentManager() – user Feb 04 '16 at 08:45
  • This is the perfect solution. Strange part is that the `getItem(int pos)` still not getting called but the viewpager is showing fragments perfectly! Any idea? – Muhammad Babar May 27 '16 at 14:17
12

Global working tested solution.

getSupportFragmentManager() keeps the null reference some times and View pager does not create new fragment instance.Since it finds reference to same fragment. So to over come this use getChildFragmentManager() solves problem in simple way.

Don't

new PagerAdapter(getSupportFragmentManager(), fragments);

Do

new PagerAdapter(getChildFragmentManager() , fragments);

Vinayak
  • 6,056
  • 1
  • 32
  • 30
2

Simple use FragmentStatePagerAdapter instead of FragmentPagerAdapter

or

you can use new MyFragmentPagerAdapter(this.getChildFragmentManager())

Hope it will help you :)

Neo
  • 3,546
  • 1
  • 24
  • 31
1

In my case I was correctly calling

MyFragmentPagerAdapter myFragmentPagerAdapter = new MyFragmentPagerAdapter(this.getChildFragmentManager());

but then in the nested fragment I was trying to replace the container fragment with another one by using:

getFragmentManager()

You need to go to the activity and call

getActivity().getSupportFragmentManager();
kingston
  • 11,053
  • 14
  • 62
  • 116
0

In my cases it worked after add this to my FragmentPagerAdapter:

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

and I also used getChildFragmentManager() like Luksprog said

Jorge Casariego
  • 21,948
  • 6
  • 90
  • 97