杂货: - 此adwidget已经在小部件树中。如何禁用此例外。这是什么意思?

问题描述 投票:0回答:7
我在列表中插入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()));
    }

In addition to Kafil Khan's 
flutter admob flutter-dependencies firebase-admob
7个回答
18
投票
, you can wrap the Container widget with

StatefulBuilder.

示例:

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

#Step-1: Make A Stateful Class Like Below:

9
投票
import 'package:flutter/cupertino.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; class BannerAdmob extends StatefulWidget{ @override State<StatefulWidget> createState() { return _BannerAdmobState(); } } class _BannerAdmobState extends State<BannerAdmob>{ late BannerAd _bannerAd; bool _bannerReady = false; @override void initState() { super.initState(); _bannerAd = BannerAd( adUnitId: "ca-app-pub-3940256099942544/6300978111", request: const AdRequest(), size: AdSize.largeBanner, listener: BannerAdListener( onAdLoaded: (_) { setState(() { _bannerReady = true; }); }, onAdFailedToLoad: (ad, err) { setState(() { _bannerReady = false; }); ad.dispose(); }, ), ); _bannerAd.load(); } @override void dispose() { super.dispose(); _bannerAd.dispose(); } @override Widget build(BuildContext context) { return _bannerReady?SizedBox( width: _bannerAd.size.width.toDouble(), height: _bannerAd.size.height.toDouble(), child: AdWidget(ad: _bannerAd), ):Container(); } }

#Step-2: Use this as below:
@override
Widget build(BuildContext context){
  return BannerAdmob();
}

问题是您一次又一次地放置相同的小部件(没有任何唯一的ID或键),您可以通过创建新的

8
投票
类并返回Adwidget来解决此问题,这将多次构建相同的小部件, it works like a Builder or you can use Future Builder This solved my problem, hope it will work for you too! :)

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

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

4
投票
BannerAd(adUnitId: 'somethingDifferentThanTheOneInTheTree')

错误日志清楚地说明:

如果将此Adwidget放在列表中,请确保在 构建器功能具有唯一的广告对象。确保您不使用 在一个以上的Adwidget中相同的AD对象。

上述

3
投票
,只是我将我的实施方式放在未来的新移民那里,以使他们更容易。

首先,让我们创建一个名为ad_helper的辅助类,以隐藏我们的UI, 其中包含两个助手方法: First方法是buildbannerwidget,它是我们希望构建我们的广告小部件的一种公共方法。

秒方法是_instantiateBanner,这是每次称为buildbannerwidget方法的私人方法。

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

我尝试了所有这些,但只有以下内容对我有用。我在每个页面上添加了

myBanner.dispose()
iniState

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

3
投票

添加一个唯一的
SizedBox
为每个包含
AdWidget

的to(或其他小部件)确实解决了我的问题。 您必须初始化并加载ADS在initstate()方法中。
这是我如何使用横幅广告键作为小部件的唯一键。
if (_bannerAd1 != null) SizedBox( key: Key(_bannerAd1!.adUnitId), height: _bannerAd1?.size.height.toDouble(), width: _bannerAd1?.size.width.toDouble(), child: AdWidget( ad: _bannerAd1!, ), ), if (_bannerAd2 != null) SizedBox( key: Key(_bannerAd2!.adUnitId), height: _bannerAd2?.size.height.toDouble(), width: _bannerAd2?.size.width.toDouble(), child: AdWidget( ad: _bannerAd2!, ), ),

2
投票

您必须使用唯一的键

class BannarAdWidget extends StatefulWidget {
 const BannarAdWidget({Key? key}) : super(key: key);

 @override
 State<BannarAdWidget> createState() => _BannarAdWidgetState();
}

class _BannarAdWidgetState extends State<BannarAdWidget> {
 BannerAd? _bannerAd;
 bool _bannerAdIsLoaded = false;

 @override
 void didChangeDependencies() {
 // Create the ad objects and load ads.
 _bannerAd = BannerAd(
  size: AdSize.banner,
  request: const AdRequest(),
  adUnitId: AdmobHelper.bannerAdUnitId,
  listener: BannerAdListener(
    onAdLoaded: (Ad ad) {
      print('$BannerAd loaded.');
      setState(() => _bannerAdIsLoaded = true);
    },
    onAdFailedToLoad: (Ad ad, LoadAdError error) {
      print('$BannerAd failedToLoad: $error');
      ad.dispose();
    },
    onAdOpened: (Ad ad) => print('$BannerAd onAdOpened.'),
    onAdClosed: (Ad ad) => print('$BannerAd onAdClosed.'),
  ),
  )..load();

 super.didChangeDependencies();
}

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

@override
Widget build(BuildContext context) {
 final BannerAd? bannerAd = _bannerAd;
 if (_bannerAdIsLoaded && bannerAd != null) {
  return SizedBox(
    height: bannerAd.size.height.toDouble(),
    width: bannerAd.size.width.toDouble(),
    child: AdWidget(ad: bannerAd),
  );
 } else {
  return const SizedBox.shrink();
 }
}



class AdmobHelper {
  static String get bannerAdUnitId {
   if (Platform.isAndroid) {
    return "ca-app-pub-3940256099942544/6300978111";
   } else if (Platform.isIOS) {
    return "ca-app-pub-3940256099942544/2934735716";
   } else {
    throw UnsupportedError('Unsupported platform');
  }
 }
}

上面没有对我有用。 
在我的案例中,我在同一列表中显示三个Adbanner,我将创建3个自变量,以加载3个独立的Adwidegt。请参阅附件的代码以具有解决此问题的Aproximation。 注意:解决了我们谈论的错误,现在我在每次横幅从屏幕上消失时都会删除内存时尚未解决横幅问题,因为滚动。每次卷轴发生时,这种力量都会重建和处置...

@override Widget build (BuildContext context) { final BannerAd? banner1 = _bannerAd1; final BannerAd? banner2 = _bannerAd2; final BannerAd? banner3 = _bannerAd3; if(widget.index==2 && _bannerAd1isAvailable && banner1 != null ){ print(banner1.adUnitId); return AdContainer(banner: banner1, numBanner: 1,); }else if(widget.index==12 && _bannerAd2isAvailable && banner2 != null ){ print(banner2.adUnitId); return AdContainer(banner: banner2, numBanner: 2,); }else if(widget.index==22 && _bannerAd3isAvailable && banner3 != null ){ print(banner3.adUnitId); return AdContainer(banner: banner3, numBanner: 3,); }else{ return Container(); } } class AdContainer extends StatelessWidget { const AdContainer({ Key? key, required this.banner, required this.numBanner, }) : super(key: key); final int numBanner; final BannerAd banner; @override Widget build(BuildContext context) { final AdWidget object1 = AdWidget(ad: banner); final AdWidget object2 = AdWidget(ad: banner); final AdWidget object3 = AdWidget(ad: banner); return Container( width: double.infinity, color: const Color.fromRGBO(13, 37, 63, 0.6), padding: const EdgeInsets.symmetric(vertical: 20,horizontal: 20), child: Container( alignment: Alignment.center, height: banner.size.height.toDouble(), width: banner.size.width.toDouble(), child: (numBanner==1)?object1:(numBanner==2)?object2:object3, ), ); } }

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.