Learning Kotlin and Jetpack Compose in Android Studio. Trying to understand recomposition.
The following code only recomposes on the first button click - why?
Output is shown below my code. Basically, the first time I click the Add New Item button the screen recomposes perfectly, but then it does not recompose again. However, if you look at the LogCat, you can see that it's still working, just not updating the screen. What am I missing?
View Model
class MainViewModel : ViewModel() {
val listLiveData: LiveData<List<Int>>
get() = newListLiveData
private val newList = ArrayList<Int>()
private val newListLiveData = MutableLiveData<List<Int>>()
fun addNewListItem(listItem: Int) {
newList.add(listItem)
newListLiveData.value = newList
println("**** addNewListItem($listItem)")
}
}
Home Screen Scaffolding and Content
@Composable
fun HomeScreen(
navController: NavHostController,
model: MainViewModel
) {
val stuff by model.listLiveData.observeAsState(emptyList())
Scaffold(
content = { Content(model, stuff) }
)
}
@Composable
fun Content(
model: MainViewModel = MainViewModel(),
stuff: List<Int>
) {
LazyColumn() {
items(items = stuff){ index ->
Text("$index")
}
}
Button(
onClick = { model.addNewListItem((0..10).random()) },
) {
Text(text = "Add Random Item to List")
}
}
LogCat Output
I/System.out: **** addNewListItem(0) <-- Recomposes fine here
I/System.out: **** addNewListItem(2) <-- Does not recompose
I/System.out: **** addNewListItem(5) <-- Does not recompose
I/System.out: **** addNewListItem(6) <-- Does not recompose
I/System.out: **** addNewListItem(4) <-- Does not recompose
Screenshot
Thank you
CodePudding user response:
Honestly speaking, as long as you do not have to do with interoperability with the View system, AVOID using anything other than the built-for-Compose MutableState<T>
objetcs. The ultra-boilerplate code of yours can simply be replaced by
ViewModel{
val cleanList by mutableStateListOf<Item>() // Initialized as an Empty list of 'Item's
fun addItem(item: Item){
cleanList.add
}
}
Within Composables,
@Composable
MyComposable(
list: List<Item>,
onAddItem: (Item) -> Unit // Receive Item, return Unit
) {
Button { // This is on-Click, assume
onAddItem(/*Add Item Here, per logic*/)
}
}
Call it anywhere like so
MyComposable(list = viewModel.cleanList, onAddItem = viewModel::addItem)
This is some fine code here. Easy to read, free of boilerplate, bafflingly beautiful and clean as a crystal.
Leverage the beauty of Compose, and ditch the ugly legacy crap.