1

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);
    }
Zain
  • 37,492
  • 7
  • 60
  • 84
  • Why are you doing any of this and not just passing your `Fragment` to your adapter directly? You control the constructor for your adapter and can pass it whatever you want. – ianhanniballake Jun 30 '20 at 21:00
  • @ianhanniballake So, I need to pass `MyFragment` as the adapter argument, and then pass it to the adapter's fragment through `getItem()` .. I will try this out .. sorry if I didn't get you much. I posted the adapter, and fragment code if that make it clearer .. Thank you – Zain Jun 30 '20 at 21:36
  • Why are you passing `requireActivity().getSupportFragmentManager()` instead of `getChildFragmentManager()` (which is always the correct thing to pass in)? – ianhanniballake Jun 30 '20 at 22:26

1 Answers1

3

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.

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • thanks for that, unfortunately that raised NPE when I tried `getChildFragmentManager().findFragmentById(R.id.myFragment)` for the returned fragment .. – Zain Jun 30 '20 at 22:41
  • Like my answer said, you'd just use `requireParentFragment()` from within one of your ViewPager fragments (as that's the parent now that you set it up with the parent's child FragmentManager) – ianhanniballake Jun 30 '20 at 22:46
  • it's now `java.lang.IllegalStateException: Fragment PagerFragment{3a76a43} (73d6dd69-0f1a-4428-8c8e-055a24fe61ae) id=0x7f0800f8} is not a child Fragment, it is directly attached to com.xx.MainActivity@e045857` – Zain Jun 30 '20 at 22:50
  • 1
    Then you haven't changed your adapter to use `getChildFragmentManager()`. – ianhanniballake Jun 30 '20 at 22:56