AdMob 插页式广告加载与显示指南:解决广告不显示问题

本文旨在解决 AdMob 插页式广告在 Android 应用中不显示的问题。核心在于理解广告加载的异步性,并确保在广告完全加载成功后才尝试显示。教程将详细讲解正确的广告加载、回调处理及显示时机,并提供优化的代码示例,帮助开发者构建稳定的广告集成方案。

1. 理解 AdMob 插页式广告的加载机制

admob 插页式广告的加载是一个异步过程。这意味着当你调用 interstitialad.load() 方法时,广告并不会立即可用。系统会在后台请求广告,并在成功或失败时通过回调通知你的应用。在广告加载完成之前,尝试显示广告将导致 interstitialad 对象为 null 或未准备好,从而广告无法显示。

原始代码中出现的问题正是由于未能正确处理这种异步性:

// 在这里你开始加载广告
mInterstitialAd = adsManager.loadInterstatialAd();

// 紧接着你试图显示广告
if (mInterstitialAd != null) {
    mInterstitialAd.show(ColoringActivity.this);
}

在 adsManager.loadInterstatialAd() 调用之后,mInterstitialAd 变量在绝大多数情况下仍然是 null,因为广告加载请求还在进行中,onAdLoaded 回调尚未触发。因此,if (mInterstitialAd != null) 条件判断失败,广告也就永远不会显示。

2. 正确的广告加载与显示流程

为了确保插页式广告能够正确显示,我们需要遵循以下步骤:

  1. 初始化 AdMob SDK: 在应用启动时完成 SDK 初始化。
  2. 加载广告: 在需要显示广告之前,提前调用加载方法。例如,在 Activity 的 onCreate() 或用户完成某个操作后。
  3. 等待加载完成: 通过 InterstitialAdLoadCallback 监听广告加载结果。
  4. 显示广告: 仅当 onAdLoaded() 回调被触发,表明广告已成功加载并准备就绪时,才调用 InterstitialAd.show() 方法。
  5. 处理广告生命周期回调: 通过 FullScreenContentCallback 监听广告的显示、关闭、点击等事件,并在此处管理广告对象的生命周期,例如在广告关闭后将 mInterstitialAd 置为 null 以便下次重新加载。

3. 优化 AdsManager 类

为了更好地管理广告的加载和显示,我们可以对 AdsManager 类进行优化,使其能够异步地处理广告加载,并在广告准备就绪时提供显示接口。

import android.app.Activity;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import com.google.android.gms.ads.AdError;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.FullScreenContentCallback;
import com.google.android.gms.ads.LoadAdError;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.interstitial.InterstitialAd;
import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback;
import com.google.android.gms.ads.initialization.InitializationStatus;
import com.google.android.gms.ads.initialization.OnInitializationCompleteListener;

public class AdsManager {

    private static final String TAG = "AdsManager";
    private Context context;
    private InterstitialAd mInterstitialAd;
    private boolean isAdLoading = false; // 标记是否正在加载广告

    public AdsManager(Context context) {
        this.context = context.getApplicationContext(); // 使用 ApplicationContext 避免内存泄漏
        MobileAds.initialize(context, new OnInitializationCompleteListener() {
            @Override
            public void onInitializationComplete(@NonNull InitializationStatus initializationStatus) {
                Log.d(TAG, "AdMob SDK initialized.");
            }
        });
    }

    /**
     * 加载插页式广告。
     * 广告加载是异步的,不应立即尝试显示。
     */
    public void loadInterstitialAd() {
        if (mInterstitialAd != null || isAdLoading) {
            Log.d(TAG, "Interstitial ad is already loaded or currently loading.");
            return;
        }

        isAdLoading = true;
        AdRequest adRequest = new AdRequest.Builder().build();

        InterstitialAd.load(context, "ca-app-pub-3940256099942544/1033173712", // 使用测试广告单元ID
                adRequest, new InterstitialAdLoadCallback() {
                    @Override
                    public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) {
                        Log.e(TAG, "Interstitial ad failed to load: " + loadAdError.getMessage());
                        mInterstitialAd = null;
                        isAdLoading = false;
                    }

                    @Override
                    public void onAdLoaded(@NonNull InterstitialAd interstitialAd) {
                        Log.d(TAG, "Interstitial ad loaded successfully.");
                        mInterstitialAd = interstitialAd;
                        isAdLoading = false;

                        // 设置全屏内容回调,处理广告的生命周期事件
                        mInterstitialAd.setFullScreenContentCallback(new FullScreenContentCallback() {
                            @Override
                            public void onAdClicked() {
                                Log.d(TAG, "Ad was clicked.");
                            }

                            @Override
                            public void onAdDismissedFullScreenContent() {
                                Log.d(TAG, "Ad was dismissed.");
                                // 广告关闭后,将广告对象置为null,以便下次重新加载
                                mInterstitialAd = null;
                                loadInterstitialAd(); // 可选:在广告关闭后立即预加载下一个广告
                            }

                            @Override
                            public void onAdFailedToShowFullScreenContent(@NonNull AdError adError) {
                                Log.e(TAG, "Ad failed to show: " + adError.getMessage());
                                // 广告显示失败,将广告对象置为null
                                mInterstitialAd = null;
                            }

                            @Override
                            public void onAdImpression() {
                                Log.d(TAG, "Ad recorded an impression.");
                            }

                            @Override
                            public void onAdShowedFullScreenContent() {
                                Log.d(TAG, "Ad showed full screen content.");
               

// 广告已显示,通常在这里可以将mInterstitialAd置为null,准备加载下一个 // 但更推荐在 onAdDismissedFullScreenContent 中处理,因为广告显示后用户可能未立即关闭 } }); } }); } /** * 显示插页式广告(如果已加载并准备就绪)。 * 只有在广告加载成功后才能调用此方法。 * * @param activity 用于显示广告的 Activity。 * @return 如果广告成功显示,返回 true;否则返回 false。 */ public boolean showInterstitialAd(Activity activity) { if (mInterstitialAd != null) { mInterstitialAd.show(activity); Log.d(TAG, "Interstitial ad is being shown."); return true; } else { Log.d(TAG, "Interstitial ad is not ready to be shown."); // 如果广告未准备好,可以尝试重新加载 loadInterstitialAd(); return false; } } /** * 检查插页式广告是否已加载并准备就绪。 * @return 如果广告已加载,返回 true;否则返回 false。 */ public boolean isAdLoaded() { return mInterstitialAd != null; } }

4. 在 Activity 中正确调用

在 Activity 中,您应该在合适的时机加载广告,并在用户触发特定事件时尝试显示广告。

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;

public class ColoringActivity extends AppCompatActivity {

    private AdsManager adsManager;
    private Button showAdButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_coloring); // 假设您的布局文件名为 activity_coloring

        adsManager = new AdsManager(this);
        // 在 Activity 创建时预加载插页式广告
        adsManager.loadInterstitialAd();

        showAdButton = findViewById(R.id.show_ad_button); // 假设您有一个按钮用于显示广告
        if (showAdButton != null) {
            showAdButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // 当用户点击按钮时,尝试显示广告
                    if (adsManager.showInterstitialAd(ColoringActivity.this)) {
                        // 广告已显示,可以在这里暂停游戏或执行其他操作
                    } else {
                        // 广告未准备好,可能需要提示用户或等待
                        // adsManager.showInterstitialAd() 内部已经尝试重新加载
                        // 可以在这里显示一个Toast提示用户稍等
                        // Toast.makeText(ColoringActivity.this, "广告正在加载中,请稍候...", Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 可以在这里再次检查广告是否加载,如果未加载则重新加载
        // 确保每次Activity回到前台时,都有广告可供显示
        if (!adsManager.isAdLoaded()) {
            adsManager.loadInterstitialAd();
        }
    }
}

布局文件 (activity_coloring.xml) 示例:




    

    

5. 其他重要配置与注意事项

  • AndroidManifest.xml 配置: 确保您的 AndroidManifest.xml 文件中包含正确的权限和 AdMob 应用 ID。

    
    
    
    
        
        
        
        
    

    注意: 原始问题中的 uses-permission android:name="android.permission.VIBRATE" 与 AdMob 无直接关系,INTERNET 权限是必需的。

  • Gradle 依赖: 在您的 build.gradle (Module: app) 文件中,确保添加了 AdMob SDK 依赖。

    dependencies {
        implementation 'com.google.android.gms:play-services-ads:22.x.x' // 使用最新稳定版本
    }

    请将 22.x.x 替换为当前最新的稳定版本。

  • 测试广告单元 ID: 在开发和测试阶段,务必使用 Google 提供的测试广告单元 ID (ca-app-pub-3940256099942544/1033173712 用于插页式广告)。这可以避免无效流量对您的 AdMob 账户产生影响。只有在应用发布前,才替换为您的实际广告单元 ID。

  • 广告预加载: 为了提供更好的用户体验,建议在用户可能需要查看广告之前就预加载广告。例如,在 Activity 启动时加载,或在用户完成一个游戏关卡后立即加载下一个广告。

  • 内存管理: 在 AdsManager 中使用 context.getApplicationContext() 可以帮助避免 Activity 内存泄漏,因为 ApplicationContext 的生命周期与应用相同,而 Activity Context 的生命周期较短。

总结

解决 AdMob 插页式广告不显示问题的关键在于正确处理其异步加载机制。通过将广告加载与显示逻辑分离,确保在 onAdLoaded 回调触发后才尝试显示广告,并利用 FullScreenContentCallback 管理广告生命周期,可以有效构建一个稳定可靠的 AdMob 广告集成方案。遵循本教程中的代码结构和最佳实践,将帮助您避免常见的集成陷阱,确保广告能够顺利展示。