Reputation: 51
I am trying to call an ad dynamically in a listview
but throws this error :
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.
Here is the code
Import package google_mobile_ads
import 'package:google_mobile_ads/google_mobile_ads.dart';
Then instantiated the package
NativeAd _nativeAd;
final Completer<NativeAd> nativeAdCompleter = Completer<NativeAd>();
I function to load the Ads
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());
}
Then to show the add I did this in a switch case statement
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;
This integration throws the above exception while showing ads from the second ad
Upvotes: 5
Views: 2406
Reputation: 21
To show multiple google native ads in flutter ListView you need to focus on the below 3 steps.
I assume you already follow the process to show Native Ads in a flutter. Create Native ads
Step 1: Create a different Future function as below in a separate dart file.
static Future<Widget> getNativeAdTest({
required BuildContext context,
}) async {
bool isAdLoaded = false;
NativeAd _listAd = NativeAd(
adUnitId: AdHelper.nativeAdUnitId,
factoryId: "listTile",
request: const AdRequest(),
listener: NativeAdListener(onAdLoaded: (ad) {
isAdLoaded = true;
if (kDebugMode) {
// print("ad load");
}
}, onAdFailedToLoad: (ad, error) {
// _listAd.dispose();
if (kDebugMode) {
print("faild to load add ${error.message}");
}
}),
);
await _listAd.load();
await Future.delayed(const Duration(seconds: 4));
return AdWidget(
ad: _listAd,
key: Key(_listAd.hashCode.toString()),
);
}
Step 2: Use ListView.separated() itemBuilder will show list content and separatorBuilder will show Ads.(you can skip if you want to use as any child)
Step 3: Use FutureBuilder() in the child widget as below to get data after ad load.
return FutureBuilder(
future: AdHelper.getNativeAdTest(context: context),
builder: (BuildContext context, snapshot) {
if (snapshot.hasData) {
AdWidget ad = snapshot.data as AdWidget;
print("snap: $snapshot");
return Container(
height: 90,
child: ad,
);
} else {
return Container(
alignment: Alignment.topCenter,
margin: const EdgeInsets.only(top: 20),
child: const CircularProgressIndicator(
value: 0.8,
));
}
});
Upvotes: 2
Reputation: 23
I'm really not sure how you have implemented the widget since you only show the part of you class but I believe it should work if you made the isolated widget for Native ad and place initialisation of NativeAd
in initState
like this.
Then you can use NativeAdWidget
in your list view.
class NativeAdWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() => NativeAdState();
}
class NativeAdState extends State<NativeAdWidget> {
NativeAd _nativeAd;
final Completer<NativeAd> nativeAdCompleter = Completer<NativeAd>();
@override
void initState() {
super.initState();
_nativeAd = NativeAd(
adUnitId: Platform.isAndroid ? getIt<Vars>().androidNativeId : getIt<Vars>().iosNativeId,
request: const AdRequest(nonPersonalizedAds: true),
customOptions: <String, Object>{},
factoryId: getIt<Vars>().admobFactoryId,
listener: AdListener(
onAdLoaded: (Ad ad) {
nativeAdCompleter.complete(ad as NativeAd);
},
onAdFailedToLoad: (Ad ad, LoadAdError err) {
unawaited(HandleError.logError(err.message));
ad.dispose();
nativeAdCompleter.completeError(null);
},
onAdOpened: (Ad ad) => print('$ad onAdOpened.'),
onAdClosed: (Ad ad) => print('$ad onAdClosed.'),
onApplicationExit: (Ad ad) => print('$ad onApplicationExit.'),
),
);
_nativeAd?.load();
}
@override
void dispose() {
super.dispose();
_nativeAd?.dispose();
_nativeAd = null;
}
@override
Widget build(BuildContext context) {
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 ad');
}
}
return Container(
height: 330,
child: child,
color: const Color(0xFFFFFFFF),
);
},
);
}
}
Upvotes: 1