Flutter :- This AdWidget is already in the Widget tree. How to disable this exception. And what does it mean?

4,221

Solution 1

I tried all of these, but only the following worked for me. I added myBanner.dispose() to iniState to each of my pages.

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

Solution 2

The problem is that you're putting the same Widget again and again. You can fix this by creating a new StatefulWidget class and returning the Adwidget, this will build that same widget multiple times, it works like a Builder. This solved my problem, hope it will work for you too! :)

You also don't have to provide multiple id's for a single ad unit.

Solution 3

In addition to Kafil Khan's answer, you can wrap the Container widget with StatefulBuilder.

Example:

Widget bannerAdWidget() {
    return StatefulBuilder(
      builder: (context, setState) => Container(
        child: AdWidget(ad: _bannerAd),
        width: _bannerAd.size.width.toDouble(),
        height: 100.0,
        alignment: Alignment.center,
      ),
    );
  }

Solution 4

When you want to add a new banner, you have to assign it a new ID:

BannerAd(adUnitId: 'somethingDifferentThanTheOneInTheTree')

As clearly stated by the error log:

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.

Solution 5

As the above answer, just I will put my implementation here for newcomers from the future to be much easier for them.

Firstly, let's create a helper class called ad_helper to hide all stuff from our UI, Which contains two helper methods :

First method is buildBannerWidget which is a public method to build our ad widget as we wish.

Second method is _instantiateBanner which is a private method to build our bannerAd object every time we call buildBannerWidget method.

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();
  }
 }

Second step is in our UI will be our widget:

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,
          );
    
      },
    )
Share:
4,221
Harsh Patel
Author by

Harsh Patel

Updated on December 28, 2022

Comments

  • Harsh Patel
    Harsh Patel over 1 year

    So I insert admob ads inside the List. And I added the functionality of infinity scroll inside the list view. So when the user scrolls to end of the list, new items are added into the list. With this items I also add admob ads inside it.

    So when the users scroll to the end the new items and ads are added into the List. At that time the below exceptions are caught. So how to solve this exception.

    ======== 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)
    

    code:-

    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()));
        }
    
  • ramenknight
    ramenknight almost 2 years
    I'm still getting the same error even with the StatefulWidget