抛出IllegalArgumentException的FragmentPagerAdapter-已添加片段 [英] FragmentPagerAdapter throwing IllegalArgumentException - Fragment Already Added

查看:81
本文介绍了抛出IllegalArgumentException的FragmentPagerAdapter-已添加片段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个ViewPagerTabLayout包含3个片段.有时,当我在(c0>的帮助下)扫过3个片段时,会抛出IllegalArgumentException并提示已添加 Fragments ... ... (位于索引0处的片段请明确点).由于错误日志仅显示与FragmentManager类有关的内容,而与我的Fragment类无关,因此可能是什么问题?以下是我正在使用的适配器

I have a ViewPager and a TabLayout containing 3 Fragments. At times when I swipe through(with the help of ViewPager) the 3 Fragments, an IllegalArgumentException is thrown with a message that Fragment is already added: ...(Fragment at index 0 to be specific). What could be the problem as the error log is only showing something to do with FragmentManager class and none of my Fragment classes? Below is the adapter(s) I am using


import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter
import androidx.fragment.app.FragmentStatePagerAdapter

data class TitledFragment(val fragment: Fragment, val title: CharSequence?)

/**
 * Should be used when displaying more than 2 [Fragment]s in a view-pager otherwise use
 * [FragmentViewPagerAdapter]
 */
@Suppress("KDocUnresolvedReference")
class FragmentStateViewPagerAdapter(
    private val titledFragmentList: List<TitledFragment>,
    fragmentManager: FragmentManager
) : FragmentStatePagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
    private val tabCount = titledFragmentList.size

    /**
     * Selects the middle or first [Fragment] as the default selected [Fragment] from a list
     * ([titledFragmentList]) of odd-numbered [Fragment]s and even-numbered [Fragment]s respectively.
     * For example, a view-pager supposed to display 3 fragments ([titledFragmentList] = 3) will have
     * it's default selected fragment position equal to 1(2nd [Fragment]) from the list whereas a
     * view-pager supposed to display 2 fragments ([titledFragmentList] = 2) will have it's default
     * selected fragment position equal to 0(1st [Fragment])
     */
    val middleFragmentPosition: Int
        get() = if (tabCount <= 0 || tabCount == 1) {
            0
        } else {
            val fl = tabCount.toFloat() / 2
            when {
                tabCount % 2 == 0 -> fl.toInt() - 1
                else -> fl.toInt()
            }
        }

    override fun getPageTitle(position: Int): CharSequence? =
        titledFragmentList[position].title ?: super.getPageTitle(position)

    override fun getItem(position: Int): Fragment = titledFragmentList[position].fragment

    override fun getCount(): Int = tabCount
}

/**
 * Should be used when displaying less than 3 [Fragment]s in a view-pager otherwise use
 * [FragmentStateViewPagerAdapter]
 */
@Suppress("KDocUnresolvedReference")
class FragmentViewPagerAdapter(
    private val titledFragmentList: List<TitledFragment>,
    fragmentManager: FragmentManager
) : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
    private val tabCount = titledFragmentList.size

    /**
     * Selects the middle or first [Fragment] as the default selected [Fragment] from a list
     * ([titledFragmentList]) of odd-numbered [Fragment]s and even-numbered [Fragment]s respectively.
     * For example, a view-pager supposed to display 3 fragments ([titledFragmentList] = 3) will have
     * it's default selected fragment position equal to 1(2nd [Fragment]) from the list whereas a
     * view-pager supposed to display 2 fragments ([titledFragmentList] = 2) will have it's default
     * selected fragment position equal to 0(1st [Fragment])
     */
    val middleFragmentPosition: Int
        get() = if (tabCount <= 0 || tabCount == 1) {
            0
        } else {
            val fl = tabCount.toFloat() / 2
            when {
                tabCount % 2 == 0 -> fl.toInt() - 1
                else -> fl.toInt()
            }
        }

    override fun getPageTitle(position: Int): CharSequence? =
        titledFragmentList[position].title ?: super.getPageTitle(position)

    override fun getItem(position: Int): Fragment = titledFragmentList[position].fragment

    override fun getCount(): Int = tabCount
}

推荐答案

我认为,不应在适配器之外保存对片段的引用.它们应该在适配器内部创建.适配器可以这样写:

I think, you shouldn't hold references to fragments outside of adapter. They should be created inside the adapter. Probably the adapter can be written this way:

class FragmentStateViewPagerAdapter(
    private val tabTitles: List<String>,
    fragmentManager: FragmentManager
) : FragmentStatePagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {

    private val tabs: List<Fragment> = (tabTitles.indices).map { YourFragment.newInstance(it) }

    override fun getCount(): Int = tabTitles.size

    override fun getItem(position: Int): Fragment = tabs[position]

    override fun getPageTitle(position: Int): CharSequence {
        // Generate a title depending on the position.
        return tabTitles[position]
    }
}

但是您的示例也可以.也许需要更多代码.同样奇怪的是,在我的情况下不需要BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT(它显示错误,但不一定).

But your example also works. Maybe more code is required. Also strangely BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT is not required in my case (it shows error, but must not).

class MainActivity : AppCompatActivity() {

    private lateinit var adapter: FragmentViewPagerAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val titledFragments = (1..3).map { TitledFragment(PlusOneFragment(), it.toString()) }
        adapter = FragmentViewPagerAdapter(titledFragments, supportFragmentManager)
        with(view_pager) {
            adapter = this@MainActivity.adapter
        }
    }
}

这篇关于抛出IllegalArgumentException的FragmentPagerAdapter-已添加片段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆