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

如何为ViewPager中每个PetFragment实例创建独立ViewModel?

实现每个petId对应独立ViewModel实例的方案

这个场景我之前做项目时也遇到过,核心就是要让ViewModel能接收petId参数,同时保证每个PetFragment实例对应专属的ViewModel。下面是具体的实现步骤和代码示例:

步骤1:定义带petId参数的ViewModel

先让你的ViewModel接受petId作为构造参数,这样它就能基于这个ID处理对应宠物的专属数据:

class PetViewModel(private val petId: String) : ViewModel() {
    // 示例:根据petId加载宠物数据
    val petData: LiveData<Pet> = repository.getPetById(petId)

    // 其他业务逻辑,比如更新宠物信息等...
}

步骤2:自定义ViewModelProvider.Factory

默认的ViewModel工厂只能创建无参的ViewModel,所以我们需要自己实现一个工厂类,让它持有petId,并在创建ViewModel时把这个参数传进去:

class PetViewModelFactory(private val petId: String) : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        // 校验ViewModel类型,避免创建错误的实例
        if (modelClass.isAssignableFrom(PetViewModel::class.java)) {
            return PetViewModel(petId) as T
        }
        throw IllegalArgumentException("传入的ViewModel类不匹配,请检查类型")
    }
}

步骤3:在PetFragment中绑定petId并获取ViewModel

通过newInstance方法把petId存入Fragment的arguments中(确保Fragment重建时petId不会丢失),然后用自定义工厂获取ViewModel:

class PetFragment : Fragment() {
    private lateinit var petId: String
    // 用Kotlin扩展函数简化ViewModel的获取逻辑
    private val viewModel: PetViewModel by viewModels {
        PetViewModelFactory(petId)
    }

    companion object {
        private const val ARG_PET_ID = "pet_id"

        fun newInstance(petId: String): PetFragment {
            return PetFragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_PET_ID, petId)
                }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 从arguments中取出petId,确保参数非空
        petId = requireArguments().getString(ARG_PET_ID)
            ?: throw IllegalArgumentException("必须传入有效的petId参数")
    }

    // 视图创建与UI逻辑
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // 这里可以直接使用viewModel中的数据更新UI
        return inflater.inflate(R.layout.fragment_pet, container, false)
    }
}

为什么这样能保证每个petId对应独立ViewModel?

  • 每个PetFragment实例的arguments中存储了唯一的petId,即使Fragment因屏幕旋转、ViewPager滑动被销毁重建,这个ID也会被系统自动保留。
  • 调用viewModels { ... }时,我们为每个Fragment传入了绑定当前petId的工厂,ViewModel会和Fragment的生命周期绑定,同时构造时携带了专属的petId,自然每个petId对应独立的ViewModel实例。

如果不用Kotlin扩展函数,也可以手动调用ViewModelProvider获取:

viewModel = ViewModelProvider(this, PetViewModelFactory(petId))[PetViewModel::class.java]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:31:05