0

I noticed in this ViewPager2 video that there are 3 different ways of declaring an adapter with Fragments. What's the difference between them and which 1 should be used for swipe views with tabs using ViewPager2?

Option 1 (recommended)

class MyFragmentAdapter (
    fa: FragmentActivity
) : FragmentStateAdapter(fa)

Option 2

class MyFragmentAdapter (
    f: Fragment
) : FragmentStateAdapter(f)

Option 3

class MyFragmentAdapter (
    fm: FragmentManager,
    l: Lifecycle
) : FragmentStateAdapter(fm, l)
wbk727
  • 8,017
  • 12
  • 61
  • 125

2 Answers2

0

These classes are all inheriting from FragmentStateAdapter. There are even more ways. You mentioned, you want to swipe between fragments in a ViewPager. Then it might be an advantage to hold neighboring fragments in memory, without destroying them. In case you don't have too many pages, I would recommend to use FragmentPagerAdapter instead. When you got a lot of fragments, you should rather use FragmentStatePagerAdapter, which is similar to FragmentStateAdapter, to improve performance.

Here is a working example:

MyPagerAdapter.kt

class MyPagerAdapter(fragmentManager: FragmentManager, private val fragments: List<Fragment>)
    : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {

    private val retainedFragments: SparseArray<Fragment> = SparseArray()

    override fun getItem(position: Int): Fragment {
        return if (retainedFragments.get(position) != null)
            retainedFragments.get(position)
        else
            fragments[position]
    }

    override fun getCount() = this.fragments.size

    override fun instantiateItem(container: ViewGroup, position: Int): Any {
        val fragment = super.instantiateItem(container, position) as Fragment
        retainedFragments.put(position, fragment)

        return fragment
    }

    override fun destroyItem(container: ViewGroup, position: Int, view: Any) {
        if (retainedFragments.get(position) != null) {
            retainedFragments.remove(position)
        }
        super.destroyItem(container, position, view)
    }

    override fun getPageTitle(position: Int): CharSequence? {
        return if (position == 0)
            context?.getString(R.string.bars_title)
        else
            context?.getString(R.string.bars_title_presets)
    }
}

Then in your host Fragment/Activity, in this case the host is a Fragment with DataBinding (not relevant here):

class HostFragment : Fragment() {
    private lateinit var pagerAdapter: MyPagerAdapter
    private val fragments: MutableList<Fragment> = mutableListOf()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        fragments.add(MyTabFragment.newInstance(0))
        fragments.add(MyTabFragment.newInstance(1))
        pagerAdapter = MyPagerAdapter(childFragmentManager, fragments)
        pagerAdapter.notifyDataSetChanged()
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        setHasOptionsMenu(false)
        val binding: FragmentBarsBinding =
            DataBindingUtil.inflate(inflater,R.layout.fragment_host, container, false)
        binding.apply {
            pager.adapter = pagerAdapter
            tabs.setupWithViewPager(pager,true)
        }
        return binding.root
    }
}
nulldroid
  • 1,150
  • 8
  • 15
  • Good question. I don't have an answer to that, because I haven't done performance testing. The description in the docs is also quite vague. It depends on how many elements or how much data your fragments are 'carrying'. I would say, 2-5 is not much. But if you got like 10-20 it would be a lot I guess. Fragments are quite heavy though. You can try it out on a real device, and you will see if UI is lagging or not. – nulldroid Mar 31 '20 at 23:17
  • This answer is about Viewpager not Viewpager2 and even references the old v4 support docs, the question is about viewpager2 not viewpager – Andrew Mar 31 '20 at 23:23
  • My bad. Haven't seen it was specifically asked about ViewPager2. Have updated the link to AndroidX though, to reference correctly at least. Can you explain why ViewPager2 should replace ViewPager, but AndroidX ViewPager is not yet deprecated? – nulldroid Mar 31 '20 at 23:33
  • @nulldroid I hope not, for now I'm sticking to AndroidX ViewPager – wbk727 Apr 01 '20 at 14:58
  • @MacaronLover me too. So far it's working seamlessly in multiple projects but according to the docs it's gonna be replaced sooner or later. My answer is quite off-topic, though. Will leave it here anyways, since it could be helpful for some people. – nulldroid Apr 01 '20 at 16:16
  • 1
    As a note, the documentation of Androidx viewpager seems to be in a mess, the Kotlin versions of all the adapters for viewpager are strikethrough'd indicating deprecation where as the Java version of the docs has a explicit note say deprecated BUT viewpager itself has not been deprecated (with viewpager you can use it without an adapter though unlike viewpager2). So it looks like they are keeping the old viewpager for use without Adapters at the moment. I too am sticking with viewpager as I'm not able to generate the same style page labels with the tablayout at the moment. – Andrew Apr 01 '20 at 18:12
  • @Andrew Thanks for that but I still [can't use `ViewPager2` with tabs](https://stackoverflow.com/questions/60821746/viewpager2-with-tablayout-not-navigating-to-correct-tab) as it doesn't navigate to the correct tab whenever I click a certain tab name in my `TabLayout` – wbk727 Apr 02 '20 at 17:41
0

With Viewpager2 there is only one adapter type FragmentStateAdapter

There does not seem to be a difference in how they behave, they are just different constructors of the same FragmentStateAdapter. Which one to use seems to mostly depend on where you are creating the viewpager2

Give it a FragmentActivity if you are creating the viewpager2 in an Activity, this is a shortcut to the third method

Give is a Fragment if you are creating the viewpager2 in a parent Fragement, this is a shortcut to the third method

The third of FragmentManager and Lifecycle is actually what it requires to work, see the source code for viewpager2 constructors https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/viewpager2/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentStateAdapter.java#109

Andrew
  • 8,198
  • 2
  • 15
  • 35