Came across a curious situation with AndroidView this morning.
I have a ProductCard interface that looks like this
interface ProductCard {
val view: View
fun setup(
productState: ProductState,
interactionListener: ProductCardView.InteractionListener
)
}
This interface can be implemented by a number of views.
A composable that renders a list of AndroidView
uses ProductCard
to get a view and pass in state updates when recomposition happens.
@Composable
fun BasketItemsList(
modifier: Modifier,
basketItems: List<ProductState>,
provider: ProductCard,
interactionListener: ProductCardView.InteractionListener
) {
LazyColumn(modifier = modifier) {
items(basketItems) { product ->
AndroidView(factory = { provider.view }) {
Timber.tag("BasketItemsList").v(product.toString())
provider.setup(product, interactionListener)
}
}
}
}
With this sample, any interaction with the ProductCard view’s (calling ProductCard.setup()
) doesn’t update the screen. Logging shows that the state gets updated but the catch is that it’s only updated once per button. For example, I have a favourites button. Clicking it once pushes a state update only once, any subsequent clicks doesn’t propagate. Also the view itself doesn’t update. It’s as if it was never clicked.
Now changing the block of AndroidView.update
to use it
and casting it as a concrete view type works as expected. All clicks propagate correctly and the card view gets updated to reflect the state.
@Composable
fun BasketItemsList(
modifier: Modifier,
basketItems: List<ProductState>,
provider: ProductCard,
interactionListener: ProductCardView.InteractionListener
) {
LazyColumn(modifier = modifier) {
items(basketItems) { product ->
AndroidView(factory = { provider.view }) {
Timber.tag("BasketItemsList").v(product.toString())
// provider.setup(product, interactionListener)
(it as ProductCardView).setup(product, interactionListener)
}
}
}
}
What am I missing here? why does using ProductCard
not work while casting the view to its type works as expected?
Update 1
Seems like casting to ProductCard
also works
@Composable
fun BasketItemsList(
modifier: Modifier,
basketItems: List<ProductState>,
provider: ProductCard,
interactionListener: ProductCardView.InteractionListener
) {
LazyColumn(modifier = modifier) {
items(basketItems) { product ->
AndroidView(factory = { provider.view }) {
Timber.tag("BasketItemsList").v(product.toString())
// provider.setup(product, interactionListener)
(it as ProductCard).setup(product, interactionListener)
}
}
}
}
So the question is why do we have to use it
inside AndroidView.update
instead of any other references to the view?