Android fragments FragmentPagerAdapter抛出IllegalArgumentException-已添加片段

Android fragments FragmentPagerAdapter抛出IllegalArgumentException-已添加片段,android-fragments,kotlin,android-viewpager,androidx,fragmentmanager,Android Fragments,Kotlin,Android Viewpager,Androidx,Fragmentmanager,我有一个ViewPager和一个TabLayout包含3个片段。当我(借助于ViewPager)浏览3个片段时,会抛出一个IllegalArgumentException,其中包含一条消息,该消息已添加片段:…(具体为索引0处的片段)。当错误日志只显示与FragmentManager类有关的内容,而没有显示我的片段类时,会出现什么问题?下面是我正在使用的适配器 import androidx.fragment.app.Fragment import androidx.fragment.app.

我有一个
ViewPager
和一个
TabLayout
包含3个片段。当我(借助于
ViewPager
)浏览3个片段时,会抛出一个
IllegalArgumentException
,其中包含一条消息,该消息已添加片段:…(具体为索引0处的片段)。当错误日志只显示与
FragmentManager
类有关的内容,而没有显示我的片段类时,会出现什么问题?下面是我正在使用的适配器


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
}

导入androidx.fragment.app.fragment
导入androidx.fragment.app.FragmentManager
导入androidx.fragment.app.FragmentPagerAdapter
导入androidx.fragment.app.FragmentStatePagerAdapter
数据类TitledFragment(val fragment:fragment,val title:CharSequence?)
/**
*在视图寻呼机中显示超过2个[Fragment]时应使用,否则使用
*[片段视图页面雷达]
*/
@抑制(“KDocUnresolvedReference”)
类FragmentStateViewPagerAdapter(
私有val标题碎片列表:列表,
碎片管理器:碎片管理器
):FragmentStatePagerAdapter(fragmentManager,行为\仅恢复\当前\片段){
private val tabCount=titledFragmentList.size
/**
*选择中间或第一个[Fragment]作为从列表中选择的默认[Fragment]
*([titledFragmentList])分别为奇数编号的[Fragment]和偶数编号的[Fragment]s。
*例如,一个应该显示3个片段([titledFragmentList]=3)的视图寻呼机将具有
*它的默认选定片段位置等于列表中的1(第二个[fragment]),而
*应该显示2个片段的视图寻呼机([titledFragmentList]=2)将具有默认值
*所选碎片位置等于0(第一个[碎片])
*/
val middleFragmentPosition:Int
get()=if(tabCount fl.toInt()-1
else->fl.toInt()
}
}
覆盖有趣的getPageTitle(位置:Int):字符序列=
titledFragmentList[位置]。标题?:super.getPageTitle(位置)
重写fun getItem(位置:Int):Fragment=titledFragmentList[position]。Fragment
重写fun getCount():Int=tabCount
}
/**
*在视图寻呼机中显示少于3[Fragment]s时应使用,否则使用
*[FragmentStateViewPagerAdapter]
*/
@抑制(“KDocUnresolvedReference”)
类碎片ViewPageRadapter(
私有val标题碎片列表:列表,
碎片管理器:碎片管理器
):FragmentPagerAdapter(fragmentManager,行为\仅恢复\当前\片段){
private val tabCount=titledFragmentList.size
/**
*选择中间或第一个[Fragment]作为从列表中选择的默认[Fragment]
*([titledFragmentList])分别为奇数编号的[Fragment]和偶数编号的[Fragment]s。
*例如,一个应该显示3个片段([titledFragmentList]=3)的视图寻呼机将具有
*它的默认选定片段位置等于列表中的1(第二个[fragment]),而
*应该显示2个片段的视图寻呼机([titledFragmentList]=2)将具有默认值
*所选碎片位置等于0(第一个[碎片])
*/
val middleFragmentPosition:Int
get()=if(tabCount fl.toInt()-1
else->fl.toInt()
}
}
覆盖有趣的getPageTitle(位置:Int):字符序列=
titledFragmentList[位置]。标题?:super.getPageTitle(位置)
重写fun getItem(位置:Int):Fragment=titledFragmentList[position]。Fragment
重写fun getCount():Int=tabCount
}

我认为,您不应该在适配器外部保留对片段的引用。它们应该在适配器内部创建。适配器可能可以这样编写:

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

middleFragmentPosition
可以很容易地简化,不使用。
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
        }
    }
}