1

I have a ExerciseDetailFragment that contains an ExerciseFragmentStatePagerAdapter to show a bunch of SupportUsFragmentCard. These cards can be swiped horizontally by the user.

enter image description here

In my ExerciseFragmentStatePagerAdapter I have the following code:

fun createFragment(position: Int): Fragment {
    val exercise = exercises[position]
    val card = SupportUsFragmentCard()
    card.setExercise(exercise) <---- this is my question/problem
    return card
}

As you can see the pager adapter just instantiates the SupportUsFragmentCard and for this the exercise needs to be passed along (the card displays some exercise information) via the setExercise.

The SupportUsFragmentCard looks like this:

open class SupportUsFragmentCard : RootFragment() {
    ...
    val viewModel: SupportUsViewModel by viewModels()
    ...

    fun setExercise(exercise: Exercise?) {
        viewModel.setExercise(exercise) <---- passes on the exercise to the viewModel
    }

It’s implementation passes along the exercise to the underlying viewModel. Which in its turn encapsulates this into a LiveData (on which the SupportUsFragmentPlain has observers but I omitted this code as its not the issue):

class SupportUsViewModel() : ViewModel() {

    //interface to the view
    fun getExercise(): LiveData<Exercise?> = exercise
    fun setExercise(execise: Exercise?) {
        exercise.value = execise. <--- updates the Livedata object
    }

    //underlying live data mutable values
    private val exercise = MutableLiveData<Exercise?>(null)
}

When this code is executed, it crashes with exception:

IllegalStateException: Can't access ViewModels from detached fragment

I think because the createFragment ends up updating the viewModel without actually already being on screen. I also feel that this way of working does not respect the MVVM architecture.

What is the correct way in this scenario, using MVVM and LiveData to initialise the SupportUsViewModel with an Exercise in the ExerciseFragmentStatePagerAdapter's createFragment function?

HixField
  • 3,538
  • 1
  • 28
  • 54
  • Ran into the same problem. I feel like the best way with respect to MVVM architecture would be to pass ExerciseRepository (or whatever your repository is) upon initializing SupportUsViewModel in the constructor then loading the Exercise directly from the DataSource into your SupportUsViewModel instead of passing it to the fragment. You can just pass an ID in a bundle for example, telling it which Exercise to load. – nulldroid May 18 '20 at 12:08

0 Answers0