1

所以我在列表中插入了 admob 广告。我在列表视图中添加了无限滚动的功能。因此,当用户滚动到列表末尾时,新项目将添加到列表中。有了这个项目,我还在其中添加了 admob 广告。

因此,当用户滚动到末尾时,会将新项目和广告添加到列表中。那时会捕获以下异常。那么如何解决这个异常。

======== Exception caught by widgets library =======================================================
The following assertion was thrown building AdWidget-[#53ef3](dirty, state: _AdWidgetState#850ac):
This AdWidget is already in the Widget tree


If you placed this AdWidget in a list, make sure you create a new instance in the builder function with a unique ad object.
Make sure you are not using the same ad object in more than one AdWidget.

The relevant error-causing widget was: 
  AdWidget-[#53ef3] file:///D:/flutter%20project/memer/lib/pages/TimeLinePage.dart:198:42
When the exception was thrown, this was the stack: 
#0      _AdWidgetState.build (package:google_mobile_ads/src/ad_containers.dart:371:7)
#1      StatefulElement.build (package:flutter/src/widgets/framework.dart:4612:27)
#2      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4495:15)
#3      StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4667:11)
#4      Element.rebuild (package:flutter/src/widgets/framework.dart:4189:5)

代码:-

return ListView.builder(itemBuilder: (context, index){
        //print(posts);
        if(posts[index] is Post){
          return posts[index];
        }
        else{
          final Container adContainer = Container(
                                  alignment: Alignment.center,
                                  child: AdWidget(key: UniqueKey(), ad: posts[index] as BannerAd),//AdmobService.createBannerAd()..load()
                                  height: 50,
                              );
                      return adContainer;
        }
      },itemCount: posts.length,
          controller: scrollController,physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()));
    }
4

5 回答 5

5

问题是您一次又一次地放置相同的小部件。您可以通过创建一个新StatefulWidget类并返回 Adwidget 来解决此问题,这将多次构建同一个小部件,它的工作方式类似于 Builder。这解决了我的问题,希望它也对你有用!:)

您也不必为单个广告单元提供多个 ID。

于 2021-06-20T06:27:55.750 回答
5

除了 Kafil Khan 的回答之外,您还可以使用StatefulBuilder.

例子:

Widget bannerAdWidget() {
    return StatefulBuilder(
      builder: (context, setState) => Container(
        child: AdWidget(ad: _bannerAd),
        width: _bannerAd.size.width.toDouble(),
        height: 100.0,
        alignment: Alignment.center,
      ),
    );
  }
于 2021-07-14T15:17:54.547 回答
4

当您想添加新横幅时,您必须为其分配一个新 ID

BannerAd(adUnitId: 'somethingDifferentThanTheOneInTheTree)

正如错误日志中明确指出的那样:

如果您将此 AdWidget 放置在列表中,请确保在构建器函数中创建一个具有唯一广告对象的新实例。确保您没有在多个 AdWidget 中使用相同的广告对象。

于 2021-04-01T08:54:58.500 回答
1

正如上面的答案,我将把我的实现放在这里,让未来的新手更容易。

首先,让我们创建一个名为 ad_helper 的辅助类来隐藏 UI 中的所有内容,其中包含两个辅助方法:

第一种方法是 buildBannerWidget,它是一种公共方法,可以根据需要构建我们的广告小部件。

第二种方法是 _instantiateBanner,这是一个私有方法,每次我们调用 buildBannerWidget 方法时都会构建我们的 bannerAd 对象。

class Ads {
 static BannerAd? _banner;

  static Future<Widget> buildBannerWidget({
    required BuildContext context,
  }) async {
    final mediaQuery = MediaQuery.of(context);

    await _instantiateBanner(
      mediaQuery.orientation,
      mediaQuery.size.width.toInt(),
    );

    return Container(
      width : MediaQuery.of(context).size.width,
      height : 70,
      child: AdWidget(ad: _banner!),
    );
  }

  static Future<BannerAd> _instantiateBanner(orientation, width) async {
    _banner = BannerAd(
      adUnitId: BannerAd.testAdUnitId,
      //  size: AdSize.banner,
      size: (await AdSize.getAnchoredAdaptiveBannerAdSize(orientation, width))!,
      request: _getBannerAdRequest(),
      listener: _buildListener(),
    );
    await _banner?.load();
    return _banner!;
  }

  static AdRequest _getBannerAdRequest() {
    return AdRequest();
  }

  static BannerAdListener _buildListener() {
    return BannerAdListener(
      onAdOpened: (Ad ad) {
        print('${Constants.Tag} BannerAdListener onAdOpened ${ad.toString()}.');
      },
      onAdClosed: (Ad ad) {
        print('${Constants.Tag} BannerAdListener onAdClosed ${ad.toString()}.');
      },
      onAdImpression: (Ad ad) {
        print(
            '${Constants.Tag} BannerAdListener onAdImpression ${ad.toString()}.');
      },
      onAdWillDismissScreen: (Ad ad) {
        print(
            '${Constants.Tag} BannerAdListener onAdWillDismissScreen ${ad.toString()}.');
      },
      onPaidEvent: (
        Ad ad,
        double valueMicros,
        PrecisionType precision,
        String currencyCode,
      ) {
        print('${Constants.Tag} BannerAdListener PaidEvent ${ad.toString()}.');
      },
      onAdLoaded: (Ad ad) {
        print('${Constants.Tag} BannerAdListener onAdLoaded ${ad.toString()}.');
      },
      onAdFailedToLoad: (Ad bannerAd, LoadAdError error) {
        bannerAd.dispose();
        print(
            '${Constants.Tag} BannerAdListener onAdFailedToLoad error is ${error.responseInfo} | ${error.message} | ${error.code} | ${error.domain}');
      },
    );
  }

  static void disposeBanner() {
   _banner?.dispose();
  }
 }

第二步是在我们的 UI 中成为我们的小部件:

FutureBuilder<Widget>(
      future: Ads.buildBannerWidget(
        context: context,
      ),
      builder: (_, snapshot) {
        if (!snapshot.hasData)return Text("No Banner yet");

          return Container(
            height: 90,
            width: MediaQuery.of(context).size.width,
            child: snapshot.data,
          );
    
      },
    )
于 2021-10-02T02:39:20.907 回答
1

我尝试了所有这些,但这对我有用。我将 myBanner.dispose() 添加到我的每个页面的 iniState 中。

void initState(){ myBanner.dispose(); myBanner.load(); super.initState();}

于 2021-11-11T02:47:33.053 回答