You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose集成Admob横幅广告 解决LazyColumn滚动重载问题

问题根因

LazyColumn 默认会回收移出可视区域、超出缓存阈值的列表项。原有实现将AdView实例的初始化、广告加载逻辑全部耦合在列表项内部的AndroidView factory中,列表项被回收时对应的AdView实例会被直接销毁。当滚动回到广告位置时,列表项重建会触发factory生成全新的AdView实例,必然导致广告重新加载,既浪费广告请求配额,也可能降低填充收益。

修复方案

核心逻辑是将AdView实例的生命周期与列表项解绑,对齐页面级生命周期:列表滚动回收时仅临时断开AdView与列表项容器的关联,不销毁AdView实例;回滚到广告位置时直接复用已加载完成的AdView,避免重复请求。
具体实现步骤:

  • 在LazyColumn作用域外通过remember持有AdView实例,广告加载逻辑仅在实例初始化时执行一次
  • 给承载广告的列表项设置固定唯一key,避免列表复用导致的位置错乱
  • 将AdView与页面生命周期绑定,仅在页面退出时执行广告销毁逻辑
  • 列表项内的AndroidView直接复用外部持有的AdView实例,禁止在factory中新建AdView

完整实现代码:

@Composable
fun MainView(){
    val context = LocalContext.current
    // 页面级持有AdView实例,生命周期和页面绑定,不受列表回收影响
    val bannerAdView = remember {
        AdView(context).apply {
            setAdSize(AdSize.BANNER)
            adUnitId = context.getString(R.string.adId)
            // 仅初始化时加载一次广告
            loadAd(AdRequest.Builder().build())
            adListener = object : AdListener() {
                override fun onAdLoaded() {
                    // 广告加载成功逻辑
                }
            }
        }
    }

    // 绑定生命周期,避免内存泄漏
    val lifecycleOwner = LocalLifecycleOwner.current
    DisposableEffect(lifecycleOwner, bannerAdView) {
        lifecycleOwner.lifecycle.addObserver(bannerAdView)
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(bannerAdView)
            // 仅页面退出时销毁广告
            bannerAdView.destroy()
        }
    }

    LazyColumn{
        // 其他列表内容
        // 给广告item设置固定唯一key
        item(key = "fixed_banner_ad_position") {
            BannerAdView(adView = bannerAdView)
        }
        // 其他列表内容
    }
}

@Composable
fun BannerAdView(adView: AdView) {
    AndroidView(
        modifier = Modifier.fillMaxWidth(),
        factory = { adView }, // 直接复用传入的已初始化AdView
        update = { /* 不需要额外处理,AdView会自动处理重新挂载后的展示 */ }
    )
}
注意事项
  • 不要在AndroidView的factory、update回调中调用loadAd(),广告仅需在AdView首次初始化时加载一次,AdView原生支持detach后重新attach的状态恢复
  • 不要在列表项滚出可视区域时调用AdView的pause()、destroy()方法,这类生命周期方法仅在整个页面退出时触发即可
  • 若列表内嵌入多个横幅广告位,需要为每个广告位提前持有独立的AdView实例,禁止同一个AdView实例挂载到多个列表项位置

内容的提问来源于stack exchange,提问作者Mayur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 08:09:25