ViewModel 架构困境
ViewModel architecture dillema
我有三个片段,每个片段都有自己的 RecyclerView。如果用户从第一个片段中选择路径,则根据选择将他带到下一个具有相关课程的片段,然后选择一门课程并转到具有相关课程的最后一个片段。所以每个RecyclerView都依赖于前一个RecyclerView的数据。
我对所有片段都使用了共享的 ViewModel,但效果不佳,因为当 activity 启动时它们都会被初始化,因为数据检索功能位于在 ViewModel 中初始化的存储库中.
我为它们中的每一个都使用了一个单独的 ViewModel,范围为 activity,但效果不佳,因为数据仅在 activity 启动时检索一次,再也不会检索,因此,当在片段之间来回导航时,会显示相同的数据和项目。
如果我将单个 ViewModel 的范围限定为片段,则后一个片段无法访问前一个片段所需的数据。
如何使用 ViewModel 架构解决这个难题?或者我应该只使用 SafeArgs 来传递数据?
CourseViewModel
class CourseViewModel(app: Application): AndroidViewModel(app) {
private val courseDataRepository = CourseRepository(app)
val courseData = courseDataRepository.courseData
val selectedCourse = MutableLiveData<Course>()
}
CourseFragment.kt
class CourseFragment : Fragment(),
CourseRecyclerAdapter.CourseItemListener {
private lateinit var viewModel: CourseViewModel
private lateinit var recyclerView: RecyclerView
private lateinit var navController: NavController
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_course, container, false)
recyclerView = view.findViewById(R.id.courseRecyclerView)
navController = Navigation.findNavController(requireActivity(), R.id.nav_host )
viewModel = ViewModelProvider(this).get(CourseViewModel::class.java)
viewModel.courseData.observe(viewLifecycleOwner, Observer {
val adapter =
CourseRecyclerAdapter(
requireContext(),
it,
this
)
recyclerView.adapter = adapter
} )
return view
}
这是我放弃之前的共享模型:
class SharedViewModel(app: Application): AndroidViewModel(app) {
private val pathDataRepository = PathRepository(app)
val pathData = pathDataRepository.pathData
val selectedPath = MutableLiveData<Path>()
private val courseDataRepository = CourseRepository(app)
val courseData = courseDataRepository.courseData
val selectedCourse = MutableLiveData<Course>()
private val lessonDataRepository = LessonRepository(app)
val lessonData = lessonDataRepository.lessonData
val selectedLesson = MutableLiveData<Lesson>()
}
如果我没理解错的话,您可以将片段构建为具有以下结构。
MainFragment
- CourseFragment
- DetailsFragment
想法是将 MainFragment
作为父级并使用 MainFragment
中的 getChildFragmentManager()
启动其他两个片段,如下所示。
getChildFragmentManager().beginTransaction()
.replace(R.id.fragment_container, courseFragment)
.addToBackStack(null).commit();
现在为 MainFragment
创建一个 ViewModel
,并将 ViewModel
的范围限定到 MainFragment
的生命周期。这将作为 CourseFragment
和 DetailsFragment
的共享 ViewModel
。您可以按如下方式访问父片段范围内的 ViewModel
(即 MainFragment
)。
SharedViewModel vm = ViewModelProviders.of(getParentFragment())
.get(SharedViewModel.class);
按照@sonnet 的建议,我通过将数据存储在 Room 数据库中然后在用户 entered/re-entered 任何片段时检索它来解决这个问题,因此限制了远程数据检索。
我有三个片段,每个片段都有自己的 RecyclerView。如果用户从第一个片段中选择路径,则根据选择将他带到下一个具有相关课程的片段,然后选择一门课程并转到具有相关课程的最后一个片段。所以每个RecyclerView都依赖于前一个RecyclerView的数据。
我对所有片段都使用了共享的 ViewModel,但效果不佳,因为当 activity 启动时它们都会被初始化,因为数据检索功能位于在 ViewModel 中初始化的存储库中.
我为它们中的每一个都使用了一个单独的 ViewModel,范围为 activity,但效果不佳,因为数据仅在 activity 启动时检索一次,再也不会检索,因此,当在片段之间来回导航时,会显示相同的数据和项目。
如果我将单个 ViewModel 的范围限定为片段,则后一个片段无法访问前一个片段所需的数据。
如何使用 ViewModel 架构解决这个难题?或者我应该只使用 SafeArgs 来传递数据?
CourseViewModel
class CourseViewModel(app: Application): AndroidViewModel(app) {
private val courseDataRepository = CourseRepository(app)
val courseData = courseDataRepository.courseData
val selectedCourse = MutableLiveData<Course>()
}
CourseFragment.kt
class CourseFragment : Fragment(),
CourseRecyclerAdapter.CourseItemListener {
private lateinit var viewModel: CourseViewModel
private lateinit var recyclerView: RecyclerView
private lateinit var navController: NavController
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_course, container, false)
recyclerView = view.findViewById(R.id.courseRecyclerView)
navController = Navigation.findNavController(requireActivity(), R.id.nav_host )
viewModel = ViewModelProvider(this).get(CourseViewModel::class.java)
viewModel.courseData.observe(viewLifecycleOwner, Observer {
val adapter =
CourseRecyclerAdapter(
requireContext(),
it,
this
)
recyclerView.adapter = adapter
} )
return view
}
这是我放弃之前的共享模型:
class SharedViewModel(app: Application): AndroidViewModel(app) {
private val pathDataRepository = PathRepository(app)
val pathData = pathDataRepository.pathData
val selectedPath = MutableLiveData<Path>()
private val courseDataRepository = CourseRepository(app)
val courseData = courseDataRepository.courseData
val selectedCourse = MutableLiveData<Course>()
private val lessonDataRepository = LessonRepository(app)
val lessonData = lessonDataRepository.lessonData
val selectedLesson = MutableLiveData<Lesson>()
}
如果我没理解错的话,您可以将片段构建为具有以下结构。
MainFragment
- CourseFragment
- DetailsFragment
想法是将 MainFragment
作为父级并使用 MainFragment
中的 getChildFragmentManager()
启动其他两个片段,如下所示。
getChildFragmentManager().beginTransaction()
.replace(R.id.fragment_container, courseFragment)
.addToBackStack(null).commit();
现在为 MainFragment
创建一个 ViewModel
,并将 ViewModel
的范围限定到 MainFragment
的生命周期。这将作为 CourseFragment
和 DetailsFragment
的共享 ViewModel
。您可以按如下方式访问父片段范围内的 ViewModel
(即 MainFragment
)。
SharedViewModel vm = ViewModelProviders.of(getParentFragment())
.get(SharedViewModel.class);
按照@sonnet 的建议,我通过将数据存储在 Room 数据库中然后在用户 entered/re-entered 任何片段时检索它来解决这个问题,因此限制了远程数据检索。