Navigating back to FragmentPagerAdapter -> fragments are empty

后端 未结 5 692
庸人自扰
庸人自扰 2020-12-04 11:23

I have a Fragment (I\'ll call it pagerFragment) that is added to the backstack and is visible. It holds a viewPager with a FragmentPagerAdapt

5条回答
  •  粉色の甜心
    2020-12-04 12:01

    I just faced the problem in our project as well. The root cause is the way the the FragmentPagerAdapter works:

    The FragmentPagerAdapter just detaches a Fragment he does not currently need from its View but does not remove it from its FragmentManager. When he wants to display the Fragment again he looks if the FragmentManager still contains the Fragment using a tag that is created from the view id of the ViewPager and the id returned by the adapters getItemId(position) call. If he finds a Fragment he just schedules an attach of the Fragment to its View within the updating transaction of the FragmentManager. Only if he does not find a Fragment this way he creates a new one using the adapters getItem(position) call!

    The problem with a Fragment containing a ViewPager with a FragmentPagerAdapter is, that the contents of the FragmentManager is never cleaned up when the containing Fragment is put to the back stack. If the containing Fragment comes back from the back stack it creates a new View but the FragmentManager still contains the fragments that were attached to the old view and the attach of an existing fragment does not work anymore.

    The easiest way to get rid of this problem is to avoid nested fragments. :)

    The second easiest way is as already mentioned in other posts to use the ChildFragmentManager for the FragmentPagerAdapter as this one gets properly updated during the life cycle of the container fragment.

    As there are projects (as my current one) where both options are not possible, I have published here a solution that works with an arbitrary FragmentManager by using the hashCode of the sub fragments as the item id of the fragment at that position. It comes at the price of storing all fragments for all positions within the adapter.

    public class MyPagerAdapter extends FragmentPagerAdapter {
    
    private static int COUNT = ...;
    private final FragmentManager fragmentManager;
    private Fragment[] subFragments = new Fragment[COUNT];
    private FragmentTransaction cleanupTransaction;
    
    public MyPagerAdapter(FragmentManager fragmentManager) {
        super(fragmentManager);
        this.fragmentManager = fragmentManager;
    }
    
    @Override
    public Fragment getItem(int position) {
        return getSubFragmentAtPosition(position);
    }
    
    @Override
    public int getCount() {
        return COUNT;
    }
    
    @Override
    public long getItemId(int position) {
        return getSubFragmentAtPosition(position).hashCode();
    }
    
    //The next three methods are needed to remove fragments no longer used from the fragment manager
    @Override
    public void startUpdate(ViewGroup container) {
        super.startUpdate(container);
        cleanupTransaction = fragmentManager.beginTransaction();
    }
    
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        super.destroyItem(container, position, object);
        cleanupTransaction.remove((Fragment) object);
    }
    
    @Override
    public void finishUpdate(ViewGroup container) {
        super.finishUpdate(container);
        cleanupTransaction.commit();
    }
    
    private Fragment getSubFragmentAtPosition(int position){
        if (subFragments[position] == null){
            subFragments[position] = ...;
        }
        return subFragments[position];
    }
    

    }

提交回复
热议问题