函数集中后RewardedAd异常,需返回广告完整播放确认值
问题分析与修复方案
你的代码核心问题在于异步逻辑处理错误,以及奖励状态的判断逻辑不符合需求,具体问题和修复如下:
主要问题点
- 同步返回异步结果:
loadRewardedAd是同步方法,但广告的加载、展示、奖励发放都是异步回调操作,你直接返回adRewardedBoolean时,回调还没执行,返回的永远是初始的false,根本拿不到真实的广告完成状态。 - 奖励状态判断错误:
- 你在
onAdDismissedFullScreenContent里把adRewardedBoolean设为true,但这个回调是广告被关闭就触发,不管用户有没有看完广告拿到奖励(比如用户中途手动关闭广告)。 - 加载失败3次就强制设为
true,这完全不符合“广告完整播放完毕”的需求,加载失败不等于用户完成了广告观看。
- 你在
- 状态未重置:每次调用
loadRewardedAd时,没有重置adRewardedBoolean、adRewardedTimes这些状态变量,导致多次调用后状态混乱。 - 递归重试风险:加载失败直接递归调用
loadRewardedAd,容易引发栈溢出或者频繁请求广告服务器的问题。
修复后的代码
我们改用回调接口来传递广告完成状态(因为异步操作无法同步返回结果),同时修正奖励判断逻辑:
//Rewarded private const val adRewardedID = "ca-app-pub-3306064401573277/5337641258" private var adRewardedIsLoading = false private var adRewarded: RewardedAd? = null private var adRewardAmount: Int = 0 private var adRewardedTimes: Int = 0 // 定义回调接口,用于通知广告是否完成并获取奖励 interface RewardedAdCallback { fun onAdRewarded(amount: Int) // 广告完成,拿到奖励 fun onAdFailed() // 广告加载/展示失败,未获得奖励 } //Call loadRewardedAd from any activities //Ads.loadRewardedAd(this, object : RewardedAdCallback { ... }) fun loadRewardedAd(context: Context, callback: RewardedAdCallback) { val activity = context as? Activity ?: run { callback.onAdFailed() return } // 正在加载时直接返回,避免重复请求 if (adRewardedIsLoading) { return } // 重置状态 adRewardedTimes = 0 adRewardAmount = 0 loadAdInternal(activity, callback) } private fun loadAdInternal(activity: Activity, callback: RewardedAdCallback) { adRewardedIsLoading = true val adRequest = AdRequest.Builder().build() RewardedAd.load(activity, adRewardedID, adRequest, object : RewardedAdLoadCallback() { override fun onAdFailedToLoad(adError: LoadAdError) { adRewardedIsLoading = false adRewarded = null if (adRewardedTimes >= 3) { // 重试3次后仍失败,通知回调 callback.onAdFailed() log("广告加载重试3次失败") } else { adRewardedTimes++ // 延迟1秒重试,避免频繁请求 activity.window.decorView.postDelayed({ loadAdInternal(activity, callback) }, 1000) log("广告加载失败,重试第${adRewardedTimes}次") } } override fun onAdLoaded(rewardedAd: RewardedAd) { adRewarded = rewardedAd adRewardedIsLoading = false adRewarded?.fullScreenContentCallback = object : FullScreenContentCallback() { override fun onAdDismissedFullScreenContent() { adRewarded = null log("广告被关闭") } override fun onAdFailedToShowFullScreenContent(adError: AdError) { adRewarded = null // 展示失败,重新加载 loadAdInternal(activity, callback) log("广告展示失败") } override fun onAdShowedFullScreenContent() { log("广告开始展示") } } // 展示广告,在奖励回调里标记广告完成 adRewarded?.show(activity) { rewardItem -> adRewardAmount = rewardItem.amount // 只有拿到奖励时,才通知广告完成 callback.onAdRewarded(adRewardAmount) log("广告播放完成,获得奖励:${adRewardAmount}") } } }) }
关键修改说明
- 改用回调接口:通过
RewardedAdCallback异步传递广告状态,解决同步方法无法返回异步结果的问题。 - 修正奖励判断逻辑:只有在广告展示后的奖励回调(
show方法的lambda参数)里,才触发onAdRewarded,确保用户确实完整观看广告并获得奖励。 - 状态重置:每次调用
loadRewardedAd时重置重试次数和奖励金额,避免状态污染。 - 安全重试:用延迟重试替代递归,避免栈溢出,同时限制重试次数(3次),防止无限请求。
- 类型安全检查:增加
context转Activity的安全判断,避免类型转换异常。
使用示例
在Activity中调用:
Ads.loadRewardedAd(this, object : Ads.RewardedAdCallback { override fun onAdRewarded(amount: Int) { // 这里处理广告完成后的逻辑,比如给用户发奖励 Toast.makeText(this@MainActivity, "获得奖励:${amount}", Toast.LENGTH_SHORT).show() } override fun onAdFailed() { // 处理广告失败的逻辑 Toast.makeText(this@MainActivity, "广告加载失败", Toast.LENGTH_SHORT).show() } })
内容的提问来源于stack exchange,提问作者Suleiman Mohammed Fahim
相关产品推荐
相关产品推荐

