https://kotlinlang.org logo
#compose
Title
# compose
y

yousefa2

03/09/2021, 9:56 AM
Came across a curious situation with AndroidView this morning. I have composable that renders a list of
AndroidView
. The
View
used for
AndroidView
is provided by a generic provider that takes in some input and outputs a
View
type.
Copy code
@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 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 card itself doesn’t updates. It’s as if it was never clicked. Now changing the block of
AndroidView.update
to cast from the
ProductCard
interface to a concrete view type works as expected. All clicks propagate correctly and the card view gets updated to reflect the state.
Copy code
@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
type not working while casting the view to it’s type is working?
z

Zach Klippenstein (he/him) [MOD]

03/09/2021, 4:57 PM
I don’t think it’s a casting thing - in the first snippet you’re calling
provider.setup
, in the second you’re calling
it.setup
. In the first case it looks like you’re calling the method on the wrong object.
y

yousefa2

03/10/2021, 1:00 PM
Both are the same object ..
provider
is a view that implements
ProductCard
. Something like
Copy code
class ProductCardView: View(), ProductCardView {
   override val view: View = this
   override fun setup(...) {}
}
So far what I’ve reached is that using
it as ProductCard
also works. So the key is using the
it
that’s passed through
AndroidView.update
but they are the same object so not sure why it wouldn’t work.
Slightly different example (takes a list of cards) but you can see from the debugger that they are the same reference
z

Zach Klippenstein (he/him) [MOD]

03/10/2021, 3:29 PM
Welp I’m out of ideas. Maybe there’s some compiler magic where it treats the lambda parameter specially somehow, and so updates only work if you go through it? But idk
y

yousefa2

03/10/2021, 5:58 PM
Yeah I am thinking some compiler magic as well. Thanks anyways!
2 Views