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

如何在另一个Activity中指定要加载的Fragment?

启动Activity时指定加载目标Fragment的最优实现方案

项目结构

(Activity -> 可挂载的Fragments)

MainActivity -> Fragment A / Fragment B

OtherActivity -> Fragment C / Fragment D

Fragment A和Fragment B均可启动OtherActivity,需求是启动时指定OtherActivity要挂载的Fragment。

现有方案的问题

1. 朴素的字符串标记传递法

通过putExtra()传递字符串标记,在OtherActivity中用when判断加载对应Fragment,示例代码:

// FragmentA.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding.btn.setOnClickListener {
        val intent = Intent(requireActivity(), OtherActivity::class.java)
        intent.putExtra("frag_tag", "FragmentC")
        requireActivity().startActivity(intent)
    }
}

// OtherActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_other)

    val fragTag = intent.getStringExtra("frag_tag")
    when(fragTag) {
        "FragmentC" -> setChangeFragment(FragmentC())
        "FragmentD" -> setChangeFragment(FragmentD())
        // 新增Fragment时需要继续添加分支
    }
}

private fun setChangeFragment(fragment: Fragment) {
    supportFragmentManager.beginTransaction()
        .replace(R.id.frame_layout, fragment)
        .commit()
}

缺点:随着可加载Fragment数量增加,when分支会越来越多,代码冗余且不易维护。

2. 错误的findFragmentById尝试

曾尝试传递Fragment布局ID,通过findFragmentById获取实例,代码如下:

// FragmentA.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    mViewDataBinding.btn.setOnClickListener {
        val intent = Intent(requireActivity(), OtherActivity::class.java)
        intent.putExtra("layout_id", R.layout.fragment_c)
        requireActivity().startActivity(intent)
    }
}

// OtherActivity.kt
private fun initFragment() {
    val layoutId = intent.getIntExtra("layout_id", 0)
    if (layoutId == 0) finish()
    else {
        // 此处逻辑错误:findFragmentById接收的是容器ID(如FrameLayout的ID),而非Fragment布局ID
        val fragment = supportFragmentManager.findFragmentById(layoutId)!!
        setChangeFragment(fragment)
    }
}

private fun setChangeFragment(fragment: Fragment) {
    supportFragmentManager.beginTransaction()
        .replace(R.id.frame_layout, fragment)
        .commit()
}

问题:findFragmentById的参数是Activity布局中Fragment容器(如FrameLayout)的ID,而非Fragment自身的布局ID,因此无法通过这种方式获取Fragment实例。

最优实现方案

推荐以下几种可扩展、易维护的方案:

方案1:传递Fragment的Class类型

利用Kotlin中Class可序列化的特性,直接传递Fragment的Class,在OtherActivity中反射实例化:

// FragmentA.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding.btn.setOnClickListener {
        val intent = Intent(requireActivity(), OtherActivity::class.java).apply {
            putExtra("FRAGMENT_CLASS", FragmentC::class.java)
        }
        requireActivity().startActivity(intent)
    }
}

// OtherActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_other)

    @Suppress("UNCHECKED_CAST")
    val fragmentClass = intent.getSerializableExtra("FRAGMENT_CLASS") as? Class<out Fragment>
    fragmentClass?.let {
        val fragment = it.newInstance()
        setChangeFragment(fragment)
    } ?: finish()
}

private fun setChangeFragment(fragment: Fragment) {
    supportFragmentManager.beginTransaction()
        .replace(R.id.frame_layout, fragment)
        .commit()
}

优势:新增Fragment时无需修改OtherActivity的逻辑,直接传递对应Class即可,扩展性极强。

方案2:使用枚举映射

定义枚举类映射Fragment类型,传递枚举值,避免字符串硬编码:

// 定义枚举类
enum class TargetFragment {
    FRAGMENT_C, FRAGMENT_D
}

// FragmentA.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding.btn.setOnClickListener {
        val intent = Intent(requireActivity(), OtherActivity::class.java).apply {
            putExtra("TARGET_FRAGMENT", TargetFragment.FRAGMENT_C)
        }
        requireActivity().startActivity(intent)
    }
}

// OtherActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_other)

    val targetFragment = intent.getSerializableExtra("TARGET_FRAGMENT") as? TargetFragment
    val fragment = when(targetFragment) {
        TargetFragment.FRAGMENT_C -> FragmentC()
        TargetFragment.FRAGMENT_D -> FragmentD()
        null -> { finish(); return }
    }
    setChangeFragment(fragment)
}

private fun setChangeFragment(fragment: Fragment) {
    supportFragmentManager.beginTransaction()
        .replace(R.id.frame_layout, fragment)
        .commit()
}

优势:避免字符串硬编码的错误,新增Fragment时只需添加枚举值和对应分支,逻辑清晰。

方案3:Fragment工厂模式

定义Fragment工厂类,统一管理Fragment的实例化,进一步解耦:

// Fragment工厂类
object FragmentFactory {
    fun createFragment(type: String): Fragment? {
        return when(type) {
            "FragmentC" -> FragmentC()
            "FragmentD" -> FragmentD()
            else -> null
        }
        // 也可以结合Class或枚举实现
    }
}

// FragmentA.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding.btn.setOnClickListener {
        val intent = Intent(requireActivity(), OtherActivity::class.java).apply {
            putExtra("FRAGMENT_TYPE", "FragmentC")
        }
        requireActivity().startActivity(intent)
    }
}

// OtherActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_other)

    val fragType = intent.getStringExtra("FRAGMENT_TYPE")
    val fragment = FragmentFactory.createFragment(fragType ?: "") ?: run {
        finish()
        return
    }
    setChangeFragment(fragment)
}

private fun setChangeFragment(fragment: Fragment) {
    supportFragmentManager.beginTransaction()
        .replace(R.id.frame_layout, fragment)
        .commit()
}

优势:将Fragment实例化逻辑集中到工厂类,Activity无需关心具体创建细节,便于统一管理和修改。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 22:16:07