Search code examples
androidandroid-fragmentsandroid-viewpagerandroid-navigation

How to access the host fragment from ViewPager page fragment using Navigation Architecture Components


I've a project that I want to migrate to Navigation Architecture Components.

Before the migration, I have an activity that has a fragment that hosts a ViewPager; and I can access a method in this fragment from the ViewPager adapter fragment by referencing the host fragment tag that I had set in the fragment transaction:

MyFragment fragment = (MyFragment ) ((MyActivity) requireActivity())
        .getSupportFragmentManager().findFragmentByTag("fragment_tag"); 
fragment.someMethodInMyFragment();

Here is a diagram that deceits a part of the migration, and what I need to access through the yellow arrow:

enter image description here

In Navigation components, I didn't find a chance to set a tag to the destination fragment that hosts the ViewPager, so that I can access it through the tag like before. Also, the ViewPager adapter fragments are not a part of the Navigation components.

What I have tried: In the ViewPager adapter fragment:

Attempt 1

MyFragment fragment = (MyFragment) getParentFragment(); // This returns the navigation host fragment. So ClassCastException is raised
fragment.someMethodInMyFragment();

Attempt 2

MyFragment fragment = (MyFragment) requireActivity().getSupportFragmentManager()
     .findFragmentById(R.id.myFragment); // id of myFragment in the nav graph.
fragment.someMethodInMyFragment(); // fragment is null

UPDATE:

posting ViewPager adapter

public class PageFragmentPagerAdapter extends FragmentStatePagerAdapter {

    public PageFragmentPagerAdapter(FragmentManager fm) {
        super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
    }

    @NonNull
    @Override
    public Fragment getItem(int position) {
        return MyPagerFragment.newInstance(position);
    }


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

}

And I setup the ViewPager in MyFragment like below

public class MyFragment extends Fragment {
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        ViewPager viewPager = view.findViewById(R.id.viewpager);
        PageFragmentPagerAdapter adapter = new PageFragmentPagerAdapter(requireActivity()
                                                   .getSupportFragmentManager());
        viewPager.setAdapter(adapter);
    }

Solution

  • Your problem is that you are using requireActivity().getSupportFragmentManager() as the FragmentManager for your adapter.

    Instead, you should always use getChildFragmentManager() for Fragments that are fully contained within another fragment - you'll note that under configuration changes or process death and recreation, this is required to restore the state of each Fragment correctly.

    When you use the child FragmentManager, then requireParentFragment() will return the correct fragment that you're looking for.