Leave a rating/review
Notes: 17. Connect LiveData to Compose UI
The student materials have been reviewed and are updated as of September 2022.
Demo
You’ll wrap up the reactive and declarative approach to your UI and state by changing all the other screens’ logic to use just the state from the ViewModel.
There’s quite a few places to do this in, so let’s get started! :]
Open the AddBookActivity, and change the code as such:
// remove state
//AddBookFormContent()
val genres by addBookViewModel.genresState.observeAsState(emptyList())
val addBookState by addBookViewModel.addBookState.observeAsState(AddBookState())
Now that you’ve removed the Activity state and updated the code to use the ViewModel, change the rest of the references.
value = addBookState.name
isInputValid = addBookState.name.isNotEmpty()
value = addBookState.description
isInputValid = addBookState.description.isNotEmpty()
onItemPicked = { genre -> addBookViewModel.genrePicked(genre) })
isEnabled = addBookState.description.isNotEmpty() && addBookState.name.isNotEmpty() && addBookState.genreId.isNotEmpty()
The changes you’ve made follow the previous approach you took. You first deleted the state within the Activity, and then you proceeded to connect the LiveData values from the ViewModel, to the UI.
After doing so, you used the newly fetched values to fill in the UI and you’ve redirected any state changes to the ViewModel! Nicely done! :]
Now move to the AddBookReviewActivity, and do the same:
// remove state
//AddBookReviewForm
val books by addBookReviewViewModel.booksState.observeAsState(emptyList())
val reviewState by addBookReviewViewModel.bookReviewState.observeAsState(AddBookReviewState())
Just like before, move on to updating the references to use the ViewModel state.
items = books
preselectedItem = reviewState.bookAndGenre
value = reviewState.bookImageUrl
isInputValid = reviewState.bookImageUrl.isNotEmpty()
currentRating = reviewState.rating
onRatingChanged = { newRating -> addBookReviewViewModel.onRatingSelected(newRating) })
value = reviewState.notes
isInputValid = reviewState.notes.isNotEmpty()
isEnabled = reviewState.bookImageUrl.isNotEmpty() &&
reviewState.notes.isNotEmpty() &&
reviewState.bookAndGenre != EMPTY_BOOK_AND_GENRE
The same thing happened here, you cleaned up the UI to just hold the compose code, and you redirected any state changes to the view model. Good job!
Again, this is tedious to do for the entire project, so let’s just skip over to the final project and see the end result.
The code changes here might take a bit of time, but it’s very much worth it! All of your UI layer classes are now much more lightweight, as they hold no logic whatsoever and your ViewModels are exposing the state and reactively updating the UI, as soon as something changes or there is some kind of user interaction.
Now build & run the app, and everything should be working just like before!
[Build & Run]
That’s just awesome! You now have much less code in your UI layer, with all the functionality like before. You also have the responsibilities completely separate, and the code is very clean and structured! :]
In the next episode, you’ll see about another way to send state within the Compose tree, called CompositionLocals. See you there!