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

Android Kotlin MVVM架构下如何从Fragment向ViewModel传变量?

带参数ViewModel的正确实现方案

1. 给UserViewModel添加带参构造函数

让ViewModel接收semesterSelected,并将参数传递给Repository:

class UserViewModel(private val semesterSelected: String) : ViewModel() {
    private val userRepository = UserRepository(semesterSelected)

    // 示例:暴露课程数据的LiveData给Fragment观察
    val coursesLiveData = userRepository.fetchCourses()
}

2. 自定义ViewModelFactory

系统默认的ViewModelProvider无法创建带参ViewModel,必须自定义Factory来处理参数传递:

class UserViewModelFactory(private val semesterSelected: String) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        require(modelClass.isAssignableFrom(UserViewModel::class.java)) {
            "不支持的ViewModel类型"
        }
        @Suppress("UNCHECKED_CAST")
        return UserViewModel(semesterSelected) as T
    }
}

3. 在Fragment中正确实例化ViewModel

禁止直接new ViewModel,必须通过ViewModelProvider结合自定义Factory获取实例:

class ViewCoursesFragment : Fragment() {
    private lateinit var userViewModel: UserViewModel
    // 假设这个变量已经通过用户选择或其他逻辑赋值
    private var semesterSelected: String = "2024-春季学期"

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // 用Factory实例化带参ViewModel
        userViewModel = ViewModelProvider(
            this,
            UserViewModelFactory(semesterSelected)
        )[UserViewModel::class.java]

        // 观察ViewModel的数据更新UI
        userViewModel.coursesLiveData.observe(viewLifecycleOwner) { courses ->
            // 这里写更新RecyclerView或其他UI的逻辑
        }

        return inflater.inflate(R.layout.fragment_view_courses, container, false)
    }
}

4. 改造UserRepository接收参数

让Repository的构造函数接收semesterSelected,用来拼接Firebase数据库路径:

class UserRepository(private val semesterSelected: String) {
    private val db = FirebaseDatabase.getInstance()
    // 使用传入的学期参数构建数据库引用路径
    private val courseRef = db.getReference("courses/$semesterSelected")

    fun fetchCourses(): LiveData<List<Course>> {
        val courseLiveData = MutableLiveData<List<Course>>()
        courseRef.addValueEventListener(object : ValueEventListener {
            override fun onDataChange(snapshot: DataSnapshot) {
                val courseList = snapshot.children.mapNotNull { it.getValue(Course::class.java) }
                courseLiveData.value = courseList
            }

            override fun onCancelled(error: DatabaseError) {
                // 处理数据库读取失败的逻辑,比如打印错误日志
                Log.e("UserRepository", "数据库读取失败: ${error.message}")
            }
        })
        return courseLiveData
    }
}

额外处理:学期参数更新场景

如果后续semesterSelected需要变更,不要直接修改ViewModel的私有参数,建议在ViewModel和Repository中添加更新方法:

// UserViewModel中添加更新方法
fun updateSemester(newSemester: String) {
    userRepository.updateSemesterPath(newSemester)
    // 重新获取新学期的课程数据
    val newCourses = userRepository.fetchCourses()
    coursesLiveData.postValue(newCourses.value)
}

// UserRepository中添加路径更新方法
fun updateSemesterPath(newSemester: String) {
    courseRef = db.getReference("courses/$newSemester")
}

之后在Fragment中,当用户切换学期时调用userViewModel.updateSemester(newSelectedSemester)即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 20:10:26