Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ViewModel in fragment clears values on screen rotation

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.

like image 858
Algar Avatar asked Jan 08 '18 13:01

Algar


People also ask

What happens to fragment when activity is rotated?

Fragments — Scenario 3: Activity with retained Fragment is rotated. The fragment is not destroyed nor created after the rotation because the same fragment instance is used after the activity is recreated. The state bundle is still available in onActivityCreated .

What happens to the activity and associated ViewModel when a device rotates?

If we rotate the screen activity will recreate, but if we use ViewModel values will be retain.

How does ViewModel retain data?

ViewModel objects are automatically retained during configuration changes so that data they hold is immediately available to the next activity or fragment instance. FYI: You can use ViewModel to preserve UI state only during a configuration change, nothing else as explained perfectly in this official doc.

Does ViewModel hold data?

ViewModel is responsible for holding and processing all the data needed for the UI. It should never access your view hierarchy (like view binding object) or hold a reference to the activity or the fragment.


1 Answers

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()
    }
}
like image 166
Algar Avatar answered Sep 27 '22 20:09

Algar