🐛 Adding multiple native ads to a listview
See original GitHub issueBug report
Describe the bug Adding multiple native ads in a listview throws the error: This AdWidget is already in the Widget tree
logs
======== Exception caught by widgets library =======================================================
The following assertion was thrown building AdWidget(dirty, state: _AdWidgetState#b7d04):
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 file:///C:/Users/user/AndroidStudioProjects/******/lib/stories/package/full_page.dart:664:53
When the exception was thrown, this was the stack:
#0 _AdWidgetState.build (package:google_mobile_ads/src/ad_containers.dart:372:7)
#1 StatefulElement.build (package:flutter/src/widgets/framework.dart:4684:27)
#2 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4567:15)
#3 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4739:11)
#4 Element.rebuild (package:flutter/src/widgets/framework.dart:4261:5)
...
====================================================================================================
Steps to reproduce
Steps to reproduce the behaviour:
I instantiated the package
code sample
NativeAd _nativeAd;
final Completer<NativeAd> nativeAdCompleter = Completer<NativeAd>();
I have a function to load the ad as follows
loadAd(){
_nativeAd = NativeAd(
adUnitId: "ca-app-pub-3940256099942544/1044960115",
request: AdRequest(),
factoryId: 'adFactoryExample',
listener: AdListener(
onAdLoaded: (Ad ad) {
print('$NativeAd loaded.');
nativeAdCompleter.complete(ad as NativeAd);
},
onAdFailedToLoad: (Ad ad, LoadAdError error) {
ad.dispose();
print('$NativeAd failedToLoad: $error');
nativeAdCompleter.completeError(null);
},
onAdOpened: (Ad ad) => print('$NativeAd onAdOpened.'),
onAdClosed: (Ad ad) => print('$NativeAd onAdClosed.'),
onApplicationExit: (Ad ad) => print('$NativeAd onApplicationExit.'),
),
);
Future<void>.delayed(Duration(seconds: 1), () => _nativeAd?.load());
}
I plan to show ads dynamically in a listview as follows
case 'ad':
loadAd();
return FutureBuilder<NativeAd>(
future: nativeAdCompleter.future,
builder: (BuildContext context, AsyncSnapshot<NativeAd> snapshot) {
Widget child;
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
case ConnectionState.active:
child = Container();
break;
case ConnectionState.done:
if (snapshot.hasData) {
child = AdWidget(ad: _nativeAd);
} else {
child = Text('Error loading $NativeAd');
}
}
return Scaffold(
body: Container(
width: double.infinity,
height: double.infinity,
margin: EdgeInsets.only(top: 100, left: 5, right: 5, bottom: 70),
child: Center(child: child),
color: Colors.black,
),
);
},
);
break;
Expected behaviour
I would like to add, preload and show multiple native ads/AdWidgets to a listview in a dynamic way.
Additional context
Additional context
I have a class that implements a NativeAdFactory in Android Studio as follows:
Layout XML : ad_unified.xml
:
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.ads.formats.UnifiedNativeAdView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="684dp"
android:layout_gravity="center"
android:background="#FFFFFF"
android:minHeight="50dp"
android:orientation="vertical">
<TextView style="@style/AppTheme.AdAttribution" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="665dp"
android:orientation="vertical"
android:paddingTop="3dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/ad_app_icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:adjustViewBounds="true"
android:paddingEnd="5dp"
android:paddingRight="5dp"
android:paddingBottom="5dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/ad_headline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#0000FF"
android:textSize="16sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/ad_advertiser"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="bottom"
android:textSize="14sp"
android:textStyle="bold" />
<RatingBar
android:id="@+id/ad_stars"
style="?android:attr/ratingBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:isIndicator="true"
android:numStars="5"
android:stepSize="0.5" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="622dp"
android:orientation="vertical">
<TextView
android:id="@+id/ad_body"
android:layout_width="match_parent"
android:layout_height="37dp"
android:textSize="12sp" />
<com.google.android.gms.ads.formats.MediaView
android:id="@+id/ad_media"
android:layout_width="411dp"
android:layout_height="496dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="5dp" />
<LinearLayout
android:layout_width="412dp"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:orientation="horizontal"
android:paddingTop="10dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/ad_price"
android:layout_width="201dp"
android:layout_height="wrap_content"
android:paddingStart="5dp"
android:paddingLeft="5dp"
android:paddingEnd="5dp"
android:paddingRight="5dp"
android:textSize="12sp" />
<TextView
android:id="@+id/ad_store"
android:layout_width="209dp"
android:layout_height="wrap_content"
android:paddingStart="5dp"
android:paddingLeft="5dp"
android:paddingEnd="5dp"
android:paddingRight="5dp"
android:textSize="12sp" />
</LinearLayout>
<Button
android:id="@+id/ad_call_to_action"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</com.google.android.gms.ads.formats.UnifiedNativeAdView>
in the Main Activity.java file :
package com.******;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin;
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin.NativeAdFactory;
public class MainActivity extends FlutterActivity {
@Override
public void configureFlutterEngine(FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
final NativeAdFactory factory = new NativeAdFactoryExample(getLayoutInflater());
GoogleMobileAdsPlugin.registerNativeAdFactory(flutterEngine, "adFactoryExample", factory);
}
@Override
public void cleanUpFlutterEngine(FlutterEngine flutterEngine) {
GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "adFactoryExample");
}
}
and in the NativeAdFactoryExample.java
I have
package com.*****;
import android.view.LayoutInflater;
import android.widget.TextView;
import com.google.android.gms.ads.VideoController;
import com.google.android.gms.ads.VideoOptions;
import com.google.android.gms.ads.formats.UnifiedNativeAd;
import com.google.android.gms.ads.formats.UnifiedNativeAdView;
import io.flutter.plugins.googlemobileads.GoogleMobileAdsPlugin.NativeAdFactory;
import java.util.Map;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RatingBar;
import com.google.android.gms.ads.formats.MediaView;
import com.google.android.gms.ads.nativead.NativeAdOptions;
class NativeAdFactoryExample implements NativeAdFactory {
private final LayoutInflater layoutInflater;
NativeAdFactoryExample(LayoutInflater layoutInflater) {
this.layoutInflater = layoutInflater;
}
@Override
public UnifiedNativeAdView createNativeAd(
UnifiedNativeAd nativeAd, Map<String, Object> customOptions) {
final UnifiedNativeAdView adView =
(UnifiedNativeAdView) layoutInflater.inflate(R.layout.ad_unified, null);
// Set the media view.
adView.setMediaView((MediaView) adView.findViewById(R.id.ad_media));
// Set other ad assets.
adView.setHeadlineView(adView.findViewById(R.id.ad_headline));
adView.setBodyView(adView.findViewById(R.id.ad_body));
adView.setCallToActionView(adView.findViewById(R.id.ad_call_to_action));
adView.setIconView(adView.findViewById(R.id.ad_app_icon));
adView.setPriceView(adView.findViewById(R.id.ad_price));
adView.setStarRatingView(adView.findViewById(R.id.ad_stars));
adView.setStoreView(adView.findViewById(R.id.ad_store));
adView.setAdvertiserView(adView.findViewById(R.id.ad_advertiser));
// The headline and mediaContent are guaranteed to be in every UnifiedNativeAd.
((TextView) adView.getHeadlineView()).setText(nativeAd.getHeadline());
adView.getMediaView().setMediaContent(nativeAd.getMediaContent());
adView.setNativeAd(nativeAd);
if (nativeAd.getBody() == null) {
adView.getBodyView().setVisibility(View.INVISIBLE);
} else {
adView.getBodyView().setVisibility(View.VISIBLE);
((TextView) adView.getBodyView()).setText(nativeAd.getBody());
}
if (nativeAd.getCallToAction() == null) {
adView.getCallToActionView().setVisibility(View.INVISIBLE);
} else {
adView.getCallToActionView().setVisibility(View.VISIBLE);
((Button) adView.getCallToActionView()).setText(nativeAd.getCallToAction());
}
if (nativeAd.getIcon() == null) {
adView.getIconView().setVisibility(View.GONE);
} else {
((ImageView) adView.getIconView()).setImageDrawable(
nativeAd.getIcon().getDrawable());
adView.getIconView().setVisibility(View.VISIBLE);
}
if (nativeAd.getPrice() == null) {
adView.getPriceView().setVisibility(View.INVISIBLE);
} else {
adView.getPriceView().setVisibility(View.VISIBLE);
((TextView) adView.getPriceView()).setText(nativeAd.getPrice());
}
if (nativeAd.getStore() == null) {
adView.getStoreView().setVisibility(View.INVISIBLE);
} else {
adView.getStoreView().setVisibility(View.VISIBLE);
((TextView) adView.getStoreView()).setText(nativeAd.getStore());
}
if (nativeAd.getStarRating() == null) {
adView.getStarRatingView().setVisibility(View.INVISIBLE);
} else {
((RatingBar) adView.getStarRatingView())
.setRating(nativeAd.getStarRating().floatValue());
adView.getStarRatingView().setVisibility(View.VISIBLE);
}
if (nativeAd.getAdvertiser() == null) {
adView.getAdvertiserView().setVisibility(View.INVISIBLE);
} else {
((TextView) adView.getAdvertiserView()).setText(nativeAd.getAdvertiser());
adView.getAdvertiserView().setVisibility(View.VISIBLE);
}
adView.setNativeAd(nativeAd);
VideoController vc = nativeAd.getVideoController();
if (vc.hasVideoContent()) {
VideoOptions videoOptions =
new VideoOptions.Builder().setStartMuted(false).setClickToExpandRequested(true).build();
NativeAdOptions adOptions =
new NativeAdOptions.Builder().setVideoOptions(videoOptions).build();
vc.play();
}
return adView;
}
}
Flutter doctor
Run flutter doctor
and paste the output below:
This is my `flutter doctor summary`
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel dev, 2.1.0-12.1.pre, on Microsoft Windows [Version 10.0.19042.631], locale en-US)
[√] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
[√] Chrome - develop for the web
[√] Android Studio (version 4.1.0)
[√] VS Code (version 1.54.2)
[√] Connected device (4 available)
• No issues found!
Flutter dependencies
Run flutter pub deps -- --style=compact
and paste the output below:
`flutter pub deps -- --style=compact` summary
Dart SDK 2.13.0-116.0.dev
Flutter SDK 2.1.0-12.1.pre
****** 1.0.0+1
dependencies:
- auto_size_text_field 0.1.7 [flutter]
- bubbled_navigation_bar 0.0.4 [flutter]
- cached_network_image 2.5.1 [flutter flutter_cache_manager octo_image]
- cloud_firestore 1.0.1 [cloud_firestore_platform_interface cloud_firestore_web firebase_core firebase_core_platform_interface flutter meta]
- cupertino_icons 1.0.2
- firebase_auth 1.0.1 [firebase_auth_platform_interface firebase_auth_web firebase_core firebase_core_platform_interface flutter meta]
- firebase_core 1.0.1 [firebase_core_platform_interface firebase_core_web flutter meta]
- firebase_storage 8.0.0 [firebase_core firebase_core_platform_interface firebase_storage_platform_interface firebase_storage_web flutter]
- flutter 0.0.0 [characters collection meta typed_data vector_math sky_engine]
- flutter_ffmpeg 0.3.1 [flutter]
- flutter_icons 1.1.0 [flutter]
- flutter_image_compress 0.7.0 [flutter]
- flutter_native_admob 2.1.0+3 [flutter]
- flutter_native_image 0.0.5+3 [flutter]
- flutter_spinkit 5.0.0 [flutter]
- flutter_widgets 0.1.12 [collection flutter html meta quiver]
- google_mobile_ads 0.11.0+3 [meta flutter]
- image_picker 0.7.2+1 [flutter flutter_plugin_android_lifecycle image_picker_platform_interface]
- international_phone_input 1.0.4 [flutter libphonenumber]
- intl 0.17.0 [clock path]
- intl_phone_field 1.4.4 [flutter]
- path_provider 2.0.1 [flutter path_provider_platform_interface path_provider_macos path_provider_linux path_provider_windows]
- progress_dialog 1.2.4 [flutter]
- provider 5.0.0 [collection flutter nested]
- scrollable_positioned_list 0.1.10 [flutter meta]
- shared_preferences 2.0.4 [meta flutter shared_preferences_platform_interface shared_preferences_linux shared_preferences_macos shared_preferences_web shared_preferences_windows]
- timeago 3.0.2
- transparent_image 1.0.0
- uuid 3.0.1 [crypto]
- video_player 1.0.1 [meta video_player_platform_interface video_player_web flutter]
- video_trimmer 1.0.0 [flutter video_player flutter_ffmpeg video_thumbnail path_provider intl path]
dev dependencies:
- flutter_test 0.0.0 [flutter test_api path fake_async clock stack_trace vector_math async boolean_selector characters charcode collection matcher meta source_span stream_channel strin
g_scanner term_glyph typed_data]
transitive dependencies:
- archive 3.1.2 [crypto path]
- async 2.5.0 [collection]
- boolean_selector 2.1.0 [source_span string_scanner]
- characters 1.1.0
- charcode 1.2.0
- clock 1.1.0
- cloud_firestore_platform_interface 4.0.0 [collection firebase_core flutter meta plugin_platform_interface]
- cloud_firestore_web 1.0.1 [cloud_firestore_platform_interface firebase_core firebase_core_web flutter flutter_web_plugins js]
- collection 1.15.0
- crypto 3.0.0 [collection typed_data]
- csslib 0.16.2 [source_span]
- fake_async 1.2.0 [clock collection]
- ffi 1.0.0
- file 6.1.0 [meta path]
- firebase_auth_platform_interface 4.0.0 [firebase_core flutter meta plugin_platform_interface]
- firebase_auth_web 1.0.2 [firebase_auth_platform_interface firebase_core firebase_core_web flutter flutter_web_plugins http_parser intl js meta]
- firebase_core_platform_interface 4.0.0 [flutter meta plugin_platform_interface]
- firebase_core_web 1.0.1 [firebase_core_platform_interface flutter flutter_web_plugins js meta]
- firebase_storage_platform_interface 2.0.0 [collection firebase_core flutter meta plugin_platform_interface]
- firebase_storage_web 1.0.1 [async firebase_core firebase_core_web firebase_storage_platform_interface flutter flutter_web_plugins http js meta]
- flutter_blurhash 0.5.0 [flutter meta]
- flutter_cache_manager 2.1.2 [flutter path_provider uuid http path sqflite pedantic clock file rxdart image]
- flutter_plugin_android_lifecycle 2.0.0 [flutter]
- flutter_web_plugins 0.0.0 [flutter js characters collection meta typed_data vector_math]
- html 0.14.0+4 [csslib source_span]
- http 0.13.0 [http_parser meta path pedantic]
- http_parser 4.0.0 [charcode collection source_span string_scanner typed_data]
- image 3.0.1 [archive meta xml]
- image_picker_platform_interface 2.0.1 [flutter meta http plugin_platform_interface]
- js 0.6.3
- libphonenumber 1.0.2 [flutter meta]
- matcher 0.12.10 [stack_trace]
- meta 1.3.0
- nested 1.0.0 [flutter]
- octo_image 0.3.0 [flutter flutter_blurhash]
- path 1.8.0
- path_provider_linux 2.0.0 [path xdg_directories path_provider_platform_interface flutter]
- path_provider_macos 2.0.0 [flutter]
- path_provider_platform_interface 2.0.1 [flutter meta platform plugin_platform_interface]
- path_provider_windows 2.0.0 [path_provider_platform_interface meta path flutter ffi win32]
- pedantic 1.11.0
- petitparser 4.0.2 [meta]
- platform 3.0.0
- plugin_platform_interface 2.0.0 [meta]
- process 4.1.0 [file path platform]
- quiver 2.1.5 [matcher meta]
- rxdart 0.25.0
- shared_preferences_linux 2.0.0 [flutter file meta path path_provider_linux shared_preferences_platform_interface]
- shared_preferences_macos 2.0.0 [shared_preferences_platform_interface flutter]
- shared_preferences_platform_interface 2.0.0 [flutter]
- shared_preferences_web 2.0.0 [shared_preferences_platform_interface flutter flutter_web_plugins meta]
- shared_preferences_windows 2.0.0 [shared_preferences_platform_interface flutter file meta path path_provider_platform_interface path_provider_windows]
- sky_engine 0.0.99
- source_span 1.8.1 [collection path term_glyph]
- sqflite 2.0.0+2 [flutter sqflite_common path]
- sqflite_common 2.0.0+2 [synchronized path meta]
- stack_trace 1.10.0 [path]
- stream_channel 2.1.0 [async]
- string_scanner 1.1.0 [charcode source_span]
- synchronized 3.0.0
- term_glyph 1.2.0
- test_api 0.2.19 [async boolean_selector collection meta path source_span stack_trace stream_channel string_scanner term_glyph matcher]
- typed_data 1.3.0 [collection]
- vector_math 2.1.0
- video_player_platform_interface 2.2.0 [flutter meta]
- video_player_web 0.1.4+1 [flutter flutter_web_plugins meta video_player_platform_interface]
- video_thumbnail 0.2.5+1 [flutter]
- win32 2.0.4 [ffi]
- xdg_directories 0.2.0 [meta path process]
- xml 5.0.2 [collection meta petitparser]
Issue Analytics
- State:
- Created 2 years ago
- Comments:5
Top Results From Across the Web
Flutter: How to Properly Load Multiple Native Ads on Listview?
My goal is to show a Native ad every 8 ListTiles. Is there a way to properly do this without using extra packages?...
Read more >[Native Ad]Loading Multiple Admob Native ads in Listview #568
Hi @ldobreira, Thanks for filing the issue. I can reproduce the issue when trying to load multiple native ads I get ad already...
Read more >How to Properly Load Multiple Admob Native Ads on Listview?
My goal is to show a Native ad every 8 ListTiles. Is there a way to properly do this without using extra packages?...
Read more >Implement Banner Ad between Listview items in a flutter.
flutter #flutterTutorial # listview #listviewseparated #bannerAds #AdmobAds#interstitialAds Show Ads between listview items in a flutter.
Read more >Can we able to display multiple AdMob ads in list view
I have one app in which I want to display multiple ads in list view. App has one recycler view & which is...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@BrianTum
As @bennyng explained in https://github.com/googleads/googleads-mobile-flutter/issues/137#issuecomment-810038342:
If any two
AdWidget
s in aListView
share aNativeAd
, you will see this error. EachAdWidget
must use a uniqueAd
.Closing this issue as working as intended. Reopen if you are still receiving the error after making the suggested changes.
Looks like the variable
NativeAd _nativeAd;
is being referenced to the same ad (the last loaded) where multiple list view items try to render it.Having instances of completer and ad per load may solve this.
For example: