AdManagerAdView not rendering ad image when off screen in LazyColumn
Asked Answered
B

1

8

I am wrapping an AdManagerAdView in an AndroidView so I can use it in Jetpack Compose. The image fails to load when I use it in a LazyColumn AND the AdManagerAdView tries to load the image before the composable is on screen.

If I scroll quickly to that element, so LazyColumn composes it AND it is on screen before the image comes back from the ad server, it works as expected.

LazyColumn {
        items(5) {
            SomeOtherComposable(it)
        }

        item {
            AndroidView(
                modifier = Modifier
                    .width(300.dp)
                    .height(250.dp)
                    .background(Color.Green),
                factory = { context ->
                    val adView = AdManagerAdView(context)
                    adView.adSize = AdSize.MEDIUM_RECTANGLE
                    adView.adUnitId = adUnitId
                    adView.loadAd(Builder().build())
                    adView
                }
            )
        }

        items(5) {
            SomeOtherComposable(it)
        }
}

For demo purposes...

@Composable
fun SomeOtherComposable(i: Int) {
    Text(
        text = "SomeOtherComposable $i",
        modifier = Modifier
            .fillMaxWidth()
            .height(320.dp)
            .background(Color.White)
    )
}

This also works fine if the wrapped AdManagerAdView is used in a non-lazy Column or any other Compose layout.

This feels like a weird timing thing in LazyColumn that just happens to manifest when the Composable isn't on screen yet since using it in a regular Column works fine under the same scenario.

Has anyone experienced anything like this?

SOLVED See my answer below

Blockus answered 30/3, 2022 at 17:50 Comment(2)
Tried running your code with adUnitId = "/6499/example/banner" and a test add loads fine.Elkeelkhound
Thanks for giving it a shot, @PylypDukhov, but I am able to reproduce it 100% of the time using the example adUnitId. It is tricky timing, which complicates things. You need to scroll until the Composable is called, but stop scrolling until the image has finished loading (which you can't really see since it is off screen), then scroll it into view to verify the behavior. Using my sample code, this means scrolling until "SomeOtherComposable 4" is on screen, then waiting a 2-5 seconds before continuing to scroll.Blockus
B
6

Ok, the issue is actually that both factory{} and update{} are called before the AndroidView has gone through the layout pass. In my steps to reproduce, the ad image is coming back and being added to the internal view before it has a measured width and height.

The solution is to delay that load call until after the layout pass using doOnLayout{} like so:

AndroidView(
        modifier = Modifier
            .width(300.dp)
            .height(250.dp)
            .background(Color.Green),
        factory = { context ->
            val adView = AdManagerAdView(context)
            adView.adSize = AdSize.MEDIUM_RECTANGLE
            adView
        },
        update = { adView ->
            adView.adUnitId = adUnitId
            adView.doOnLayout {
                adView.loadAd(Builder().build())
            }
        }
    )
Blockus answered 13/4, 2022 at 22:32 Comment(2)
Oh can you explain how did you find out about when are factory and update called, I would like to know more about that.Ribal
Sorry about the late reply, but I just put some temporary logging in place to identify the order of the various calls.Blockus

© 2022 - 2024 — McMap. All rights reserved.