ViewModel in fragment clears values on screen rotation
C

1

12

Guess I'm missing something obvious here but... I'm storing data in uiModel in the DiaryViewModel class, and since I use architecture components I'm expecting the data to be retained through screen rotation - but it doesn't. I'm blind to why.

Here's a stripped down fragment

class DiaryFragment: Fragment() {
    private lateinit var viewModel: DiaryViewModel

    override onCreateView(...) {
        viewModel = ViewModelProviders.of(this).get(DiaryViewModel::class.java)
        viewModel.getModel().observe(this, Observer<DiaryUIModel> { uiModel ->
            render(uiModel)
        })
    }
}

And the corresponding view model.

class DiaryViewModel: ViewModel() {
    private var uiModel: MutableLiveData<DiaryUIModel>? = null

    fun getModel(): LiveData<DiaryUIModel> {
        if (uiModel == null) {
            uiModel = MutableLiveData<DiaryUIModel>()
            uiModel?.value = DiaryUIModel()
        }

        return uiModel as MutableLiveData<DiaryUIModel>
    }
}

Can any one see what's missing in this simple example? Right now, uiModel is set to null when rotating the screen.

Cog answered 8/1, 2018 at 13:1 Comment(4)
What version of support libraries are you using? v26.1.0 included support for Lifecycles (though not certain that would be cause of issue you're seeing)Corpuz
@JohnO'Reilly 27.0.2. I've also read that this might be the issue, but that it was fixed in version 26. Guess I'm facing something different.Cog
This might be related to lifecycle of the fragment....not necessarily a solution in itself but what I typically do is pass activity in to ViewModelProviders.of() but you'd also need to check that that makes sense for your particular use case (example of doing that is shown in developer.android.com/topic/libraries/architecture/…)Corpuz
Indeed. I tried that but it didn't work :/ Made no difference.Cog
C
27

The issue was with how the activity was handling the fragment creation. MainActivity was always creating a new fragment per rotation, as in

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    supportFragmentManager
        .beginTransaction()
        .replace(overlay.id, DiaryFragment.newInstance())
        .commit()
}

But of course, it works much better when checking if we have a saved instance, as in

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    if (savedInstanceState == null) {
        supportFragmentManager
            .beginTransaction()
            .replace(overlay.id, DiaryFragment.newInstance())
            .commit()
    }
}
Cog answered 10/1, 2018 at 9:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.