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

Flutter实现onPressed等待广告加载完成的问题求助

解决Flutter插屏广告点击按钮后等待加载的问题

问题核心

点击按钮时广告尚未加载完成,当前代码仅做一次_isAdLoaded判断,若此时为false则后续流程完全中断,加载弹窗无法关闭也不会继续执行广告展示和页面跳转。

解决方案:通过Completer等待广告加载状态变更

我们可以用Completer来监听广告加载的完成事件,确保点击按钮后能等待广告加载完成再执行后续操作,同时处理加载失败的边界情况。

步骤1:添加状态监听变量

在_BusTestState类中添加Completer变量:

Completer<void>? _adLoadCompleter;

步骤2:初始化与绑定广告加载事件

修改_initAd()方法,初始化Completer并在广告加载成功/失败时完成它:

void _initAd() {
  _adLoadCompleter = Completer(); // 初始化Completer
  InterstitialAd.load(
    adUnitId: 'ca-app-pub-3940256099942544/1033173712',
    request: AdRequest(),
    adLoadCallback: InterstitialAdLoadCallback(
      onAdLoaded: onAdLoaded,
      onAdFailedToLoad: (error) {
        print(error);
        _adLoadCompleter?.completeError(error); // 加载失败时标记错误
      },
    ),
  );
}

void onAdLoaded(InterstitialAd ad) {
  _interstitialAd = ad;
  _isAdLoaded = true;
  _adLoadCompleter?.complete(); // 加载完成时完成Completer
  _interstitialAd.fullScreenContentCallback = FullScreenContentCallback(
    onAdDismissedFullScreenContent: (ad) {
      _initAd(); // 重新加载广告时重置Completer
      ad.dispose();
    },
    onAdFailedToShowFullScreenContent: (ad, error) {
      print(error);
      _initAd(); // 重新加载广告时重置Completer
      ad.dispose();
    },
  );
}

步骤3:修改按钮点击逻辑

更新按钮的onPressed方法,等待广告加载完成后再执行操作:

onPressed: () async {
  adScreenLoadingDialog(context);
  try {
    // 等待广告加载完成,设置10秒超时避免无限等待
    await _adLoadCompleter?.future.timeout(const Duration(seconds: 10));
    
    if (_isAdLoaded && _interstitialAd != null) {
      await _interstitialAd!.show();
      Navigator.pop(context);
      Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => BusTest1()),
      );
    } else {
      throw Exception('广告未加载完成');
    }
  } catch (e) {
    Navigator.pop(context);
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('广告加载失败,请稍后重试')),
    );
  }
},

完整修改后的代码

import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';

class BusTest extends StatefulWidget {
  @override
  _BusTestState createState() => _BusTestState();
}

class _BusTestState extends State<BusTest> {
  InterstitialAd? _interstitialAd;
  bool _isAdLoaded = false;
  Completer<void>? _adLoadCompleter; // 新增Completer

  void _initAd() {
    _adLoadCompleter = Completer();
    InterstitialAd.load(
      adUnitId: 'ca-app-pub-3940256099942544/1033173712',
      request: AdRequest(),
      adLoadCallback: InterstitialAdLoadCallback(
        onAdLoaded: onAdLoaded,
        onAdFailedToLoad: (error) {
          print(error);
          _adLoadCompleter?.completeError(error);
        },
      ),
    );
  }

  void onAdLoaded(InterstitialAd ad) {
    _interstitialAd = ad;
    _isAdLoaded = true;
    _adLoadCompleter?.complete();
    _interstitialAd!.fullScreenContentCallback = FullScreenContentCallback(
      onAdDismissedFullScreenContent: (ad) {
        _initAd();
        ad.dispose();
      },
      onAdFailedToShowFullScreenContent: (ad, error) {
        print(error);
        _initAd();
        ad.dispose();
      },
    );
  }

  @override
  void initState() {
    super.initState();
    _initAd();
  }

  @override
  void dispose() {
    _interstitialAd?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: const Text(
          "Bus Test",
          style: TextStyle(fontSize: 20),
        ),
      ),
      body: SingleChildScrollView(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 16),
              child: Column(
                children: [
                  ElevatedButton(
                    style: ButtonStyle(
                      shape: MaterialStateProperty.all(
                        RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(10),
                        ),
                      ),
                      maximumSize: MaterialStateProperty.resolveWith((states) => const Size(double.infinity, 60)),
                      padding: MaterialStateProperty.all(EdgeInsets.zero),
                      backgroundColor: MaterialStateProperty.resolveWith((states) {
                        return states.contains(MaterialState.pressed) ? const Color(0xff795368) : const Color(0xff3E2A35);
                      }),
                    ),
                    onPressed: () async {
                      adScreenLoadingDialog(context);
                      try {
                        await _adLoadCompleter?.future.timeout(const Duration(seconds: 10));
                        if (_isAdLoaded && _interstitialAd != null) {
                          await _interstitialAd!.show();
                          Navigator.pop(context);
                          Navigator.push(
                            context,
                            MaterialPageRoute(builder: (context) => BusTest1()),
                          );
                        } else {
                          throw Exception('广告未加载完成');
                        }
                      } catch (e) {
                        Navigator.pop(context);
                        ScaffoldMessenger.of(context).showSnackBar(
                          const SnackBar(content: Text('广告加载失败,请稍后重试')),
                        );
                      }
                    },
                    child: const SizedBox(
                      height: 40,
                      child: Center(
                        child: Text(
                          'Bus Test 1',
                          style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15),
                        ),
                      ),
                    ),
                  ),
                  const SizedBox(height: 10),
                  // 其余两个按钮重复相同逻辑即可
                  ElevatedButton(
                    style: ButtonStyle(
                      shape: MaterialStateProperty.all(
                        RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(10),
                        ),
                      ),
                      maximumSize: MaterialStateProperty.resolveWith((states) => const Size(double.infinity, 60)),
                      padding: MaterialStateProperty.all(EdgeInsets.zero),
                      backgroundColor: MaterialStateProperty.resolveWith((states) {
                        return states.contains(MaterialState.pressed) ? const Color(0xff795368) : const Color(0xff3E2A35);
                      }),
                    ),
                    onPressed: () async {
                      adScreenLoadingDialog(context);
                      try {
                        await _adLoadCompleter?.future.timeout(const Duration(seconds: 10));
                        if (_isAdLoaded && _interstitialAd != null) {
                          await _interstitialAd!.show();
                          Navigator.pop(context);
                          Navigator.push(
                            context,
                            MaterialPageRoute(builder: (context) => BusTest2()),
                          );
                        } else {
                          throw Exception('广告未加载完成');
                        }
                      } catch (e) {
                        Navigator.pop(context);
                        ScaffoldMessenger.of(context).showSnackBar(
                          const SnackBar(content: Text('广告加载失败,请稍后重试')),
                        );
                      }
                    },
                    child: const SizedBox(
                      height: 40,
                      child: Center(
                        child: Text(
                          'Bus Test 2',
                          style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15),
                        ),
                      ),
                    ),
                  ),
                  const SizedBox(height: 10),
                  ElevatedButton(
                    style: ButtonStyle(
                      shape: MaterialStateProperty.all(
                        RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(10),
                        ),
                      ),
                      maximumSize: MaterialStateProperty.resolveWith((states) => const Size(double.infinity, 60)),
                      padding: MaterialStateProperty.all(EdgeInsets.zero),
                      backgroundColor: MaterialStateProperty.resolveWith((states) {
                        return states.contains(MaterialState.pressed) ? const Color(0xff795368) : const Color(0xff3E2A35);
                      }),
                    ),
                    onPressed: () async {
                      adScreenLoadingDialog(context);
                      try {
                        await _adLoadCompleter?.future.timeout(const Duration(seconds: 10));
                        if (_isAdLoaded && _interstitialAd != null) {
                          await _interstitialAd!.show();
                          Navigator.pop(context);
                          Navigator.push(
                            context,
                            MaterialPageRoute(builder: (context) => BusTest3()),
                          );
                        } else {
                          throw Exception('广告未加载完成');
                        }
                      } catch (e) {
                        Navigator.pop(context);
                        ScaffoldMessenger.of(context).showSnackBar(
                          const SnackBar(content: Text('广告加载失败,请稍后重试')),
                        );
                      }
                    },
                    child: const SizedBox(
                      height: 40,
                      child: Center(
                        child: Text(
                          'Bus Test 3',
                          style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15),
                        ),
                      ),
                    ),
                  ),
                  const SizedBox(height: 10),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

void adScreenLoadingDialog(BuildContext context) {
  showDialog(
    barrierDismissible: false,
    context: context,
    builder: (context) {
      return const AlertDialog(
        elevation: 0,
        backgroundColor: Colors.transparent,
        content: SizedBox(
          height: 100,
          width: 100,
          child: SpinKitCircle(
            color: Color(0xffd88820),
            size: 100,
          ),
        ),
      );
    },
  );
}

// 占位页面类,实际项目中替换为真实页面
class BusTest1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) => Scaffold(appBar: AppBar(title: const Text('Bus Test 1')));
}

class BusTest2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) => Scaffold(appBar: AppBar(title: const Text('Bus Test 2')));
}

class BusTest3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) => Scaffold(appBar: AppBar(title: const Text('Bus Test 3')));
}

关键优化点

  1. 等待机制:通过Completer实现异步等待,确保广告加载完成后再执行后续操作
  2. 错误处理:捕获加载失败和超时异常,关闭弹窗并提示用户
  3. 资源管理:广告展示后及时释放资源,重新加载广告时重置Completer
  4. 超时控制:添加10秒超时,避免用户无限等待

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 03:40:16