Kotlin Android App Open Ads首次启动onStart无法展示问题
问题根因
首次启动广告无法展示是两个时序逻辑错误导致的:
- 生命周期回调顺序不对:应用冷启动时,
ProcessLifecycleOwner的onStart回调早于首个Activity的生命周期方法执行。此时currentActivity还没通过ActivityLifecycleCallbacks完成赋值,为null,不满足广告展示的宿主Activity要求。 - 广告加载时机太晚:第一次触发
onStart调用展示逻辑时,广告还没开始拉取;广告加载是异步网络请求,等广告返回结果时onStart的执行流程已经走完,自然不会触发展示。等你退出应用切回前台时,之前触发加载的广告已经准备完成,currentActivity也有了有效值,所以能正常展示。
修复方案
1. 调整广告预加载时机
不要等要展示广告的时候才发起加载请求,等AdMob SDK初始化完成后立刻预加载广告,提前留出广告加载的时间窗口,同时避免SDK未初始化就发请求导致加载失败。
修改MyApplication代码:
class MyApplication : Application() { private var appOpenManager: AppOpenManager? = null override fun onCreate() { super.onCreate() appOpenManager = AppOpenManager(this) ProcessLifecycleOwner.get().lifecycle.addObserver(appOpenManager!!.defaultLifecycleObserver) MobileAds.initialize(this) { Log.d("tag", "MobileAds init ") // SDK初始化完成后触发第一次广告预加载 appOpenManager?.fetchAd() } } }
注意要把AppOpenManager里的fetchAd方法的可见性从private改成public,方便在Application里调用。
2. 补全空判断与冷启动展示逻辑
给广告展示逻辑加非空校验,同时在首个Activity获取到焦点(onActivityResumed)时补一次展示检查,解决冷启动时的时序冲突;另外增加冷启动标记,避免重复展示。
修改AppOpenManager代码:
首先新增冷启动标记变量:
class AppOpenManager(private val myApplication: MyApplication) : Application.ActivityLifecycleCallbacks, LifecycleObserver { private var appOpenAd: AppOpenAd? = null private var loadCallback: AppOpenAd.AppOpenAdLoadCallback? = null private var currentActivity: Activity? = null private var isShowingAd = false // 新增冷启动标记 private var isColdStart = true // ... 其余原有变量不变
然后修改showAdIfAvailable方法,增加空判断,优化失败重试逻辑:
fun showAdIfAvailable() { Log.d("tag", "isShowing:$isShowingAd - hasAd:$isAdAvailable - hasActivity:${currentActivity != null}") // 同时满足 未在展示、有可用广告、有有效Activity 三个条件才展示 if (!isShowingAd && isAdAvailable && currentActivity != null) { Log.d("tag", "show ad") val fullScreenContentCallback: FullScreenContentCallback = object : FullScreenContentCallback() { override fun onAdDismissedFullScreenContent() { appOpenAd = null isShowingAd = false // 广告关闭后预加载下一次的广告 fetchAd() } override fun onAdFailedToShowFullScreenContent(p0: AdError) { isShowingAd = false // 展示失败重新拉取广告 fetchAd() } override fun onAdShowedFullScreenContent() { isShowingAd = true // 广告展示完成后关闭冷启动标记 isColdStart = false } } appOpenAd!!.fullScreenContentCallback = fullScreenContentCallback appOpenAd!!.show(currentActivity!!) } else { Log.d("tag", "can't show ad") // 没可用广告时才触发拉取,避免重复请求 if (!isAdAvailable) { fetchAd() } } }
然后修改onActivityResumed回调,补冷启动的展示检查:
override fun onActivityResumed(activity: Activity) { currentActivity = activity // 冷启动场景下,Activity拿到焦点后补一次展示检查,解决时序问题 if (isColdStart) { showAdIfAvailable() } }
把原来init块里的fetchAd()调用删掉,避免SDK未初始化就发起广告请求。
原有DefaultLifecycleObserver里的onStart逻辑保留即可,用来处理应用切后台回前台的热启动广告展示场景。
注意事项
- 不要在广告加载完成的
onAdLoaded回调里直接调用show方法,此时大概率Activity还没完成渲染,容易出现展示异常、崩溃或者广告政策违规问题。 - 开发测试阶段请使用官方提供的测试广告位ID,使用正式ID频繁触发请求、展示很容易被判定为异常流量,导致广告位被限制填充。
- 如果你的应用有启动页(SplashActivity),建议把广告展示逻辑绑定到SplashActivity的生命周期,而不是全局ProcessLifecycle,避免在其他页面切回时误弹广告。
内容的提问来源于stack exchange,提问作者Marwan Talal
相关产品推荐
相关产品推荐

