【问题标题】:ViewPager2 adapters - difference between FragmentActivity / Fragment / FragmentManagerViewPager2 适配器 - FragmentActivity / Fragment / FragmentManager 之间的区别
【发布时间】:2020-03-31 22:00:54
【问题描述】:

我在ViewPager2 video 中注意到,有 3 种不同的方式可以使用Fragments 声明适配器。它们之间有什么区别,哪个 1 应该用于使用 ViewPager2 的标签滑动视图?

选项 1(推荐)

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

选项 2

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

选项 3

class MyFragmentAdapter (
    fm: FragmentManager,
    l: Lifecycle
) : FragmentStateAdapter(fm, l)

【问题讨论】:

    标签: android kotlin android-adapter android-viewpager2


    【解决方案1】:

    这些类都继承自 FragmentStateAdapter。还有更多的方法。您提到过,您想在 ViewPager 中的片段之间滑动。那么将相邻的片段保存在内存中而不破坏它们可能是一个优势。 如果您没有太多页面,我建议您改用FragmentPagerAdapter。当 Fragment 很多时,最好使用类似于 FragmentStateAdapter 的 FragmentStatePagerAdapter 来提高性能。

    这是一个工作示例:

    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)
        }
    }
    

    然后在你的宿主 Fragment/Activity 中,在这种情况下宿主是一个带有 DataBinding 的 Fragment(这里不相关):

    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-5并不多。但如果你得到10-20,我猜会很多。碎片虽然很重。你可以在真机上试一试,看看 UI 有没有卡顿。
    • 这个答案是关于 Viewpager 而不是 Viewpager2 甚至引用了旧的 v4 支持文档,问题是关于 viewpager2 而不是 viewpager
    • 我的错。还没有看到有人专门询问过 ViewPager2。不过,已经更新了指向 AndroidX 的链接,至少可以正确引用。你能解释一下为什么 ViewPager2 应该取代 ViewPager,而 AndroidX ViewPager 还没有被弃用吗?
    • @nulldroid 我希望不是,现在我坚持使用 AndroidX ViewPager
    • 请注意,Androidx viewpager 的文档似乎一团糟,viewpager 的所有适配器的 Kotlin 版本都带有删除线,表示弃用,因为文档的 Java 版本有明确的注意说已弃用但 viewpager 本身并未被弃用(使用 viewpager 您可以在没有适配器的情况下使用它,尽管与 viewpager2 不同)。所以看起来他们目前正在保留旧的查看器以供在没有适配器的情况下使用。我也坚持使用 viewpager,因为目前我无法使用 tablayout 生成相同样式的页面标签。
    【解决方案2】:

    Viewpager2 只有一种适配器类型FragmentStateAdapter

    它们的行为方式似乎没有区别,它们只是同一个 FragmentStateAdapter 的不同构造函数。使用哪一个似乎主要取决于您在哪里创建 viewpager2

    如果您在 Activity 中创建 viewpager2,请给它一个 FragmentActivity,这是第三种方法的快捷方式

    Give 是Fragment,如果您在父 Fragment 中创建 viewpager2,这是第三种方法的快捷方式

    FragmentManagerLifecycle 中的第三个其实是它工作所需要的,查看viewpager2 构造函数的源代码https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/viewpager2/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentStateAdapter.java#109

    【讨论】:

      猜你喜欢
      • 2012-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-10
      • 1970-01-01
      • 2021-09-18
      • 1970-01-01
      • 2014-03-03
      相关资源
      最近更新 更多