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
相关产品推荐
相关产品推荐

