How can I use FragmentFactory with FragmentStatePagerAdapter

1k views Asked by At

I like the approach of FragmentFactory, which makes it possible to pass dependencies to a fragment in a constructor.

I'd like to use a custom FragmentFactory together with a FragmentStatePagerAdapter.

I'm hosting the view pager in an activity. I can create a custom fragment factory and assign it to the activity using

supportFragmentManager.fragmentFactory = CustomFragmentFactory()

I can then use supportFragmentManager to initialize my FragmentStatePagerAdapter. That's fine so far.

My problem is that my fragments within the view pager show data dependent on the position.

Let's say I have a list items and ItemFragment, which is shown in a view pager showing items[position], hence have a constructor like this:

class ItemFragment(val item: Item) : Fragment()

How must I implement the CustomFragmentFactory and FragmentStatePagerAdapter's getItem(position: Int) function to achieve a safe equivalent of this:

override fun getItem(position: Int) = ItemFragment(items[position])
2

There are 2 answers

0
Peter F On BEST ANSWER

FragmentFactory doesn't provide a way to pass dynamic data. Hence, FragmentFactorydoesn't work in this scenario.

If you have dynamic arguments you have to pass the them the classic way using a bundle (or use an approach like Safe Args, which generates code using a bundle).

This article talks about the exact same scenario:

The limitation of using FragmentFactory is that we can’t pass dynamic arguments to it.

Let’s say we have a ViewPager that display’s two instances of the same mainFragment but with different textToDisplay values then this won’t be possible using the fragmentFactory implementation.

2
Nynuzoud On

First of all, FragmentStatePagerAdapter is deprecated now. So, it's better to use FragmentStateAdapter with ViewPager2.

I couldn't find any proper solution in case if you need to pass something into Fragment's constructor with ViewPager2 because it ignores FragmentFactory. I was thinking about implementing the FragmentFactory in createFragment method of FragmentStateAdapter but don't know where to get the proper class loader in this case.

The only solution I found is to use FragmentManager.FragmentLifecycleCallbacks. Here you have a fragment so you can cast it to you particular implementation. You can set callbacks or whatever you want to your fragment after its (re)creation. So in this case you don't need to pass something in to fragment's constructor but also can avoid creating Bundles.

fragmentManager?.registerFragmentLifecycleCallbacks(object : FragmentManager.FragmentLifecycleCallbacks() {
        override fun onFragmentPreCreated(fm: FragmentManager, f: Fragment, savedInstanceState: Bundle?) {
            super.onFragmentPreCreated(fm, f, savedInstanceState)
        }
    }, true)

I tested this code using childFragmentManager and it works fine. But I have to admit that this is not a clear solution. And if you can avoid passing something to Fragment's constructor while using FragmentStateAdapter, avoid it. Because the most proper solution is to use a FragmentFactory.

Also, as an option, your fragment knows about the parent Activity. So, you can do callbacks directly to the parent Activity.

Link to documentation: https://developer.android.com/reference/androidx/fragment/app/FragmentManager#registerFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks,%20boolean)