103

I have a fragment interface with tabs along the bottom which open different fragments in the main view.

I have one particular fragment which is a list of items. If the user selects one of the items in this list, another fragment opens which contains a viewpager which scrolls horizontally between all of the items in the list in the previous fragment. This works great.

The viewpager uses a FragmentPagerAdapter to display the items.

The problem comes when the user selects an item in the list, views it, then hits the button on the tab bar to go back to the list, then selects another item. The second time an item is selected, a blank screen appears instead of the viewpager. I receive no errors in my LogCat when this happens.

Why is the viewpager only appearing the first time?

FragmentPagerAdapter:

public class ViewPagerAdapter extends FragmentPagerAdapter {
    Cursor mCursor;

    public ViewPagerAdapter(FragmentManager fm, Cursor c) {
        super(fm);
        mCursor = c;
    }

    public void changeCursor(Cursor c) {
        mCursor = c;
        this.notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        if (mCursor == null) return 0;
        else return mCursor.getCount();
    }

    @Override
    public Fragment getItem(int position) {
        mCursor.moveToPosition(position);
        return TeamCardFragment.newInstance(mCursor, position);
    }
}

PagerFragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);

    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);

    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();

    return mView;
}

private class setAdapterTask extends AsyncTask<Void, Void, Void> {
    protected Void doInBackground(Void... params) {
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        mViewPager.setAdapter(mAdapter);
        mViewPager.setCurrentItem(mCursorPosition);
    }
}
blahdiblah
  • 33,069
  • 21
  • 98
  • 152
howettl
  • 12,419
  • 13
  • 56
  • 91

15 Answers15

223

I had the same issue. Changing the parent class of my PageAdapter from android.support.v4.app.FragmentPagerAdapter to android.support.v4.app.FragmentStatePagerAdapter solve my ViewPager display issue on "second time"!

Sufian
  • 6,405
  • 16
  • 66
  • 120
Yann
  • 3,841
  • 1
  • 22
  • 14
  • 2
    No kidding? I don't have this code anymore otherwise I would test it. Perhaps this answer will help somebody else. – howettl Dec 12 '11 at 17:50
  • 10
    What a man! I was on the lookout for this solution for days! Thanks a ton man, works like a charm. But the developer in me is asking what impact does that change make? I mean why didn't it work before and why in StatePagerAdapter – Anand Sainath Mar 04 '13 at 16:08
  • 1
    also you need to @Override public int getItemPosition (Object object) { return POSITION_NONE; } – Helin Wang Aug 30 '13 at 22:29
  • 1
    Worked for me too. Here is a link. It seems to save the fragment state, which makes all the difference. http://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html – Tjaart Jan 28 '14 at 12:04
  • finding it hard to see any situation where you would use fragmentpageradapter instead of fragmentstatepageradapter, is fragmentpageradapter more efficient? – I'm_With_Stupid Oct 14 '14 at 20:33
  • This solution doesn't require FragmentActivtiy so you can continue to use native Fragments from API 13! Should be accepted answer – ruX May 27 '15 at 12:35
  • or android.support.v13.app.FragmentStatePagerAdapter for android.app.FragmentManager and not android.support.v4.app.FragmentManager – Moisés Sep 18 '15 at 12:23
  • I see that FragmentStatePagerAdapter makes onCreate() to be called on the fragment before onCreateView(), while FragmentPagerAdapter just calls onCreateView() on the second show of the fragment. – Yar Jun 23 '16 at 17:36
  • @espa_network if you have a pager is inside a fragment, then it probably won't work, because nested fragments are not supported **yet** – William Kinaan Dec 27 '16 at 12:57
  • 1
    It's a coincidence this works, the right answer is @Daniel F's one. Anyway, for convenience of the commenters here, the difference between `FragmentPagerAdapter` and `FragmentStatePagerAdapter` is in the former being more suited for few pages, it retains all of the fragments in memory thus having best performances on page switch, while the latter is more suited for a lot of pages, it destroys fragments, keeping only their state, it's more memory efficient but a little slower on page switch. – CristinaTheDev Jun 20 '17 at 15:39
  • Wow... Spent hours on this. So strange. Thank you!! – Offek Jun 19 '19 at 15:25
90

I managed to solve this by replacing getFragmentManager() with getChildFragmentManager() in the parent fragment. This parent fragment was instancing an android.support.v4.app.FragmentPagerAdapter in order to contain pageable (slideable) fragments, which requires a fragment manager in the constructor. To this constructor I passed the return value of getChildFragmentManager().

hackbod's link was key (https://developer.android.com/about/versions/android-4.2.html#NestedFragments), which was found in this post Fragments within Fragments

To nest a fragment, simply call getChildFragmentManager() on the Fragment in which you want to add a fragment. This returns a FragmentManager that you can use like you normally do from the top-level activity to create fragment transactions.

lucidbrot
  • 5,378
  • 3
  • 39
  • 68
Daniel F
  • 13,684
  • 11
  • 87
  • 116
  • Thankyou... i was having a similar issue trying to re-instantiate a sliding tabs view after onresume() that contained a fragmentpageradapter... the tutorial i used was from 2016 and i still needed to change it to fragmentstatepageradapter to get it to work. wish I knew WHY. – Nerdy Bunz May 22 '16 at 08:32
  • this answer saved lot of my time. Because only using `FragmentStatePagerAdapter` doesnot solve the question asked here. along with `FragmentStatePagerAdapter` in parent fragment `YourAdapter adapter = new YourAdapter (getChildFragmentManager());` has to be added – MMK Aug 11 '18 at 17:09
18

for me i had to call this on my viewpager:

myViewPager.setSaveFromParentEnabled(false);

I had the issue where the viewpager was not refreshing and all i saw was a blank white screen where the fragments should be. I was passing in getChildFragmentManager but it did not help.

j2emanue
  • 60,549
  • 65
  • 286
  • 456
  • 1
    Why in the world did this work? This fixed my issue but i have no clue why. – ClayHerendeen Oct 31 '17 at 20:41
  • I removed it from my code now. The fragment manager was causing the issue. Try toggling between getchildfragmentmanager and getfragmentmanager – j2emanue Nov 01 '17 at 01:27
  • I have already tried that. I have nested Tabs each with ViewPagers that have disabled swiping. I know this is poor design but its the clients wishes not mine. Im using a childFragmentManager for the top level tabbar. Toggling for the lower level tabbar/viewpager didnt seem to fix the issue. I suppose I will stick with the setSaveFromParentEnabled(false) for now since it is working. – ClayHerendeen Nov 01 '17 at 13:39
  • Are you using the latest support library – j2emanue Nov 01 '17 at 17:31
  • 2
    I was facing the same issue from last 2 days.. Your solution worked for me. thanks ! – brijexecon Feb 06 '18 at 14:42
  • Hi @j2emanue Your solution worked for me but i don't know why getchildfragmentmanager did not worked for me and i was facing issue only in case when i go from left drawer fragment. But I think it is cauasing little bit performance issue – Jishant Feb 07 '18 at 11:44
  • myViewPager.setSaveFromParentEnabled(false) worked for me, for the case of Android N 'recents' screen (when holding on square button to open miltwindow frames). Previously ViewPager with FragmentStatePagerAdapter turned blank. – Kurovsky Apr 26 '19 at 09:55
  • you guys need to stop using this and fix start using getchildfragmentmanager that should resolve this issue in my opinion. i gave this answer at the time i was not using getchildfragmentmanager. after swapping it correctly this fix was not needed. but maybe every situation is different. visit Yashaswi N P answer first and if that does not work then fall back to mine. – j2emanue Apr 27 '19 at 04:38
  • @j2emanue I tried other solutions but only yours worked. But is this solution good for performance ? I'm not sure. – Mehmet Gür Jun 02 '20 at 12:17
  • your not using getChildFragmentManager correctly is my first guess @MehmetGür – j2emanue Jun 05 '20 at 10:04
  • Yo. where how and why did this work!!!. This answer needs upvote! +1 from me – Sachin K Pissay Nov 10 '20 at 16:05
11

In my very particular case, where I was using a CoordinatorLayout with an AppBarLayout and the ViewPager, what solved it for me was removing the android:fitsSystemWindows="true" from my AppBarLayout xml properties.

Don't ask me why. I know it sounds a little bit ridiculous and like it should have no correlation, but it was this single line the only thing that was causing trouble as I was already using getChildFragmentManager() in my adapter. I spent a whole day debugging my code just to find this, so I hope it saves someone else some time.

emirua
  • 498
  • 5
  • 14
  • 3
    Oh man... I was almost gonna surrender with this issue. You made my freaking day! Geez Google, WTF is wrong with the AppBarLayout? I've looked almost hundred pages and spent a ton of hours debugging trying to solve this issue without luck. I'm really grateful that i finally managed to solve the issue with your comment. Thanks a lot! PS: I was so desperate that I even created an issue in the AOSP: https://code.google.com/p/android/issues/detail?id=230905&can=4&sort=-opened&colspec=ID%20Status%20Priority%20Owner%20Summary%20Stars%20Reporter%20Opened XD – Guillem Roca Feb 21 '17 at 15:50
  • Thanks for the hint. At least it has helped us in resolving issue. Now we are trying to find out option for making it full screen – Paresh Mayani Jun 12 '18 at 08:29
  • You are a lifesaver! I was absolutely clueless why I was having this issue and still clueless why it worked! – nandu Jul 17 '19 at 14:02
10

I had the same issue for which I changed adapter from FragmentPagerAdapter to FragmentStatePagerAdapter and getFragmentManager() in the parent fragment to getChildFragmentManager()

The reason behind this is FragmentStatePagerAdapter is helpful in storing a large number of pages and memory associated with each page visited is less as it keeps only the saved state of the fragment while the page is not visible. This reduces the overhead while switching between the fragments.

Gowthaman M
  • 8,057
  • 8
  • 35
  • 54
Yashaswi N P
  • 896
  • 8
  • 15
4

Try to put setOffscreenPageLimit (int limit) on parent ViewPager.

mViewPager.setOffscreenPageLimit(totalPages-1);

This worked for me like charm.

In my case I had fragment inside TabLayout with ViewPager.

And another ViewPager inside that fragment. First time all working fine but when I change tab and return back, some of my fragment gone blank.

Rumit Patel
  • 8,830
  • 18
  • 51
  • 70
3

This would help you.

    viewPager.setOffscreenPageLimit(position);
1

I was getting this same problem on Xamarin Android with a blank screen the second time around.. Setting the following fixed it for me.

viewPager.SaveFromParentEnabled = false;
Gowthaman M
  • 8,057
  • 8
  • 35
  • 54
Gerard
  • 11
  • 2
1

class ViewPagerAdapter extends FragmentStatePagerAdapter this work for me try this

1

simply call getChildFragmentManager() in adapter .Then you will not get blank in multiple click

Mario Petrovic
  • 7,500
  • 14
  • 42
  • 62
1

We got around this by re-implementing the view pager items as standard views rather than fragments and changing the adapter accordingly.

howettl
  • 12,419
  • 13
  • 56
  • 91
  • you can try removing the isViewFromObject(View view, Object object) function – Mina Wissa Apr 05 '12 at 14:04
  • There's gotta be a better way.... :/ although the more I dig into Android the less mature I realize it is. – StackOverflowed May 30 '12 at 20:10
  • 1
    [Nested fragments are not supported](http://stackoverflow.com/questions/6847460/fragments-within-fragments/6847770#6847770), so re-implementing with standard view seems the good way to go. – Sylphe Sep 04 '12 at 09:05
  • I'm struggling with similar issue. I tried using PagerAdapter instead of FragmentAdapter still I encounter the same issue. Please help me out ! – Gaurav Arora Jan 18 '13 at 11:50
  • If you want to use nested fragments you can use the adapter I provided in this answer : http://stackoverflow.com/questions/7700226/display-fragment-viewpager-within-a-fragment/18234088#18234088 – Slickelito Aug 14 '13 at 14:16
0

You can also initialize the adapter for cases where you experience this error when your app is minimized and later called up.

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);
    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);
    initViewPagerAdapter();
    return mView;
}
private void initViewPagerAdapter(){
    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();
}

@Override
public void onResume(){
    super.onResume();
    initViewPagerAdapter();
}
Patrick
  • 5
  • 2
  • 5
0

I had the same thing, in the second time i call the Pager Adapter, the child view return a NullPointerException. And changing the adapder in FragmentStatePagerAdapter solve my issue too.

Arka-57
  • 41
  • 5
0

Change FragmentPagerAdapter into FragmentStatePagerAdapter Use getChildFragmentManager() instead of getFragmentManager()

getChildFragmentManager() - because according to documentation, it will return a private FragmentManager for placing and managing Fragments inside of this Fragment. Meanwhile getFragmentManager() will return the FragmentManager for interacting with fragments associated with this activity

Mostafa Anter
  • 3,445
  • 24
  • 26
0

I had a similar issue using ViewPager2 and FragmentStateAdapter. When replacing the Fragment (containing a viewpager2 and tabs of fragments) I realized the onDestroyView() method was being called after the new fragment was set up. I fixed this by calling FragmentTransaction.popBackStack() before replacing the fragment, which seemed to clean up the old fragment before creating the new one.

This issue started for me after updating androidx.appcompat:appcompat beyond version 1.2. My Fragment also used to use setRetainInstance(false) which is now deprecated, I'm unsure if that was part of the issue.