问题
I noticed in this ViewPager2 video that there are 3 different ways of declaring an adapter with Fragment
s. 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)
回答1:
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
}
}
回答2:
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
来源:https://stackoverflow.com/questions/60960621/viewpager2-adapters-difference-between-fragmentactivity-fragment-fragmentm