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 的生命周期。这将作为 CourseFragmentDetailsFragment 的共享 ViewModel。您可以按如下方式访问父片段范围内的 ViewModel(即 MainFragment)。

SharedViewModel vm = ViewModelProviders.of(getParentFragment())
                         .get(SharedViewModel.class);

按照@sonnet 的建议,我通过将数据存储在 Room 数据库中然后在用户 entered/re-entered 任何片段时检索它来解决这个问题,因此限制了远程数据检索。