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

Flutter应用Admob Banner广告仅抽屉页面切换后显示的问题求助

Flutter Admob Banner广告加载成功但不显示的问题排查与解决

环境说明

  • Flutter版本:稳定版3.22.2
  • 依赖包:google_mobile_ads、provider(均为最新版本)
  • 目标平台:Android

问题详情

实际应用场景

  • 广告加载成功(控制台输出加载日志),但屏幕底部无广告显示
  • 仅通过Drawer导航切换到其他页面再返回时,广告才会显示;切换过程中无广告关闭日志
  • 使用TextButton切换页面再返回,广告仍不显示,仅抽屉导航切换有效

最小复现应用场景

  • 修复AndroidManifest.xml格式后解决了调试安装超时问题,但广告显示异常依旧
  • 广告加载成功但不显示,热重载/重启无效,仅保存main.dart文件(Ctrl+S)时广告才出现

最小复现代码

import 'dart:async';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:provider/provider.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  MobileAds.instance.initialize();

  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider<AdsProvider>(
          create: (context) => AdsProvider(),
        ),
      ],
      child: const MyApp(),
    ),
  );
}

class AdsHelper {
  static String bannerHomePage() {
    if (Platform.isAndroid) {
      return "ca-app-pub-3940256099942544/9214589741";
    } else {
      return "";
    }
  }
}

class AdsProvider with ChangeNotifier {
  bool isBannerHomePageLoaded = false;
  late BannerAd bannerHomePage;

  void initializeBannerHomePage() async {
    bannerHomePage = BannerAd(
      size: AdSize.banner,
      adUnitId: AdsHelper.bannerHomePage(),
      listener: BannerAdListener(
        onAdLoaded: (ad) {
          isBannerHomePageLoaded = true;
          log("HomePage BannerAd loaded!");
        },
        onAdClosed: (ad) {
          ad.dispose();
          isBannerHomePageLoaded = false;
        },
        onAdFailedToLoad: (ad, err) {
          isBannerHomePageLoaded = false;
          log(err.toString());
        },
      ),
      request: AdRequest(),
    );
    await bannerHomePage.load();
    notifyListeners();
  }
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        scaffoldBackgroundColor: const Color.fromARGB(255, 234, 153, 153),
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    super.initState();

    AdsProvider adsProvider = Provider.of<AdsProvider>(context, listen: false);
    adsProvider.initializeBannerHomePage();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: ListView(
        children: [
          Text("Lable 01"),
          Text("Lable 02"),
          Text("Lable 03"),
          Text("Lable 04"),
        ],
      ),
      bottomNavigationBar: Consumer<AdsProvider>(
        builder: (context, adsProvider, child) {
          if (adsProvider.isBannerHomePageLoaded) {
            return Container(
              height: adsProvider.bannerHomePage.size.height.toDouble(),
              child: AdWidget(
                ad: adsProvider.bannerHomePage,
              ),
            );
          } else {
            return Container(
              height: 0,
            );
          }
        },
      ),
    );
  }
}

AndroidManifest.xml配置

<!-- AdMob app ID: (测试用ID) -->
<meta-data
    android:name="com.google.android.gms.ads.APPLICATION_ID"
    android:value="ca-app-pub-3940256099942544~3347511713"/>

解决方案

1. 修正状态通知时机

将notifyListeners()移到广告状态变化的回调中,确保UI在广告真正加载完成/失败时及时刷新:

class AdsProvider with ChangeNotifier {
  bool isBannerHomePageLoaded = false;
  BannerAd? bannerHomePage; // 改为可空类型,避免初始化风险

  void initializeBannerHomePage() {
    bannerHomePage?.dispose(); // 先释放旧广告实例,避免内存泄漏
    bannerHomePage = BannerAd(
      size: AdSize.banner,
      adUnitId: AdsHelper.bannerHomePage(),
      listener: BannerAdListener(
        onAdLoaded: (ad) {
          isBannerHomePageLoaded = true;
          log("HomePage BannerAd loaded!");
          notifyListeners(); // 加载完成后通知UI刷新
        },
        onAdClosed: (ad) {
          ad.dispose();
          isBannerHomePageLoaded = false;
          notifyListeners(); // 状态变化后通知UI
        },
        onAdFailedToLoad: (ad, err) {
          isBannerHomePageLoaded = false;
          log(err.toString());
          ad.dispose(); // 加载失败也要释放实例
          notifyListeners(); // 状态变化后通知UI
        },
      ),
      request: AdRequest(),
    );
    bannerHomePage!.load();
  }

  @override
  void dispose() {
    bannerHomePage?.dispose(); // 页面销毁时释放广告实例
    super.dispose();
  }
}

2. 延迟初始化广告

在initState中使用addPostFrameCallback延迟初始化,确保Widget树构建完成后再获取Provider:

class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      final adsProvider = Provider.of<AdsProvider>(context, listen: false);
      adsProvider.initializeBannerHomePage();
    });
  }
  // ... 其他代码
}

3. 规范广告容器配置

使用SizedBox.shrink()替代高度为0的Container,同时确保广告容器占满宽度:

bottomNavigationBar: Consumer<AdsProvider>(
  builder: (context, adsProvider, child) {
    if (adsProvider.isBannerHomePageLoaded && adsProvider.bannerHomePage != null) {
      return Container(
        width: double.infinity,
        height: adsProvider.bannerHomePage!.size.height.toDouble(),
        child: AdWidget(ad: adsProvider.bannerHomePage!),
      );
    } else {
      return const SizedBox.shrink();
    }
  },
),

问题根源说明

  • 原代码中notifyListeners()在load()后立即调用,此时广告并未真正加载完成,UI无法感知状态变化
  • 直接在initState中获取Provider可能存在上下文未就绪的问题
  • 未正确管理广告实例的生命周期,可能导致内存泄漏或状态异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 18:33:11