You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ViewPager2使用FragmentStateAdapter动态移除替换Fragment不生效

问题原因

FragmentStateAdapter 内部通过唯一ID缓存Fragment实例,默认实现会直接把position作为itemId返回。你当前实现中position=1的位置虽然切换了nextFragment指向的实例,但itemId始终为1,Adapter会判定该位置的Fragment没有变化,直接复用缓存里的旧F2实例,不会调用createFragment()生成新的F3,自然不会显示新页面。

修复方案
  • 重写getItemId()为每个不同的Fragment返回唯一稳定ID,让Adapter能识别到同位置下Fragment实例已经变更
  • 重写containsItem()匹配ID校验逻辑,保证Adapter能正确移除失效的旧Fragment缓存
  • 每次更新要展示的Fragment类型后调用notifyDataSetChanged()主动触发刷新
  • 不要在Adapter中手动持有Fragment实例引用,实例创建逻辑全部放在createFragment()中交给FragmentManager管理,避免状态错乱

修正后的PagerAdapter代码

import androidx.recyclerview.widget.RecyclerView

class PagerAdapter(
    fragment: PagerFragment,
) : FragmentStateAdapter(fragment) {

    // 标记当前要展示的二级页面类型:-1=无二级页,1=F2,2=F3
    private var currentSecondPageType: Int = -1
    private val firstPageItemId = 0L

    override fun getItemCount(): Int {
        // 没有二级页的时候只展示F1
        return if (currentSecondPageType == -1) 1 else 2
    }

    override fun createFragment(position: Int): Fragment {
        return when (position) {
            0 -> F1()
            1 -> when (currentSecondPageType) {
                1 -> F2()
                2 -> F3()
                else -> DummyDialogFragment()
            }
            else -> throw IndexOutOfBoundsException("Invalid position: $position")
        }
    }

    override fun getItemId(position: Int): Long {
        return when (position) {
            0 -> firstPageItemId
            // 不同二级页返回不同ID,保证Adapter能识别到实例变更
            1 -> currentSecondPageType.toLong()
            else -> RecyclerView.NO_ID
        }
    }

    override fun containsItem(itemId: Long): Boolean {
        return itemId == firstPageItemId || itemId == currentSecondPageType.toLong()
    }

    fun setNextFragment(page: Int) {
        currentSecondPageType = page
        // 通知Adapter数据集变更,触发旧缓存清理和新Fragment创建
        notifyDataSetChanged()
    }
}

修正后的跳转方法

fun navigateTo(page: Int) {
    adapter.setNextFragment(page)
    binding?.viewPager?.currentItem = if (page == 0) 0 else 1
}

注意:你之前设置的binding?.viewPager?.isSaveEnabled = false可以删掉,正确实现ID逻辑后ViewPager2的状态保存机制可以正常工作,不需要关闭。

内容的提问来源于stack exchange,提问作者mefahimrahman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 04:39:20