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
相关产品推荐
相关产品推荐

