Skip to content

Commit 3bf94e5

Browse files
committed
refactor(ads): convert AdmobNativeAdWidget to StatefulWidget
- AdmobNativeAdWidget is now a StatefulWidget to properly manage the lifecycle of the native ad object. - Added logic to dispose of the native ad when the widget is removed from the tree or when the underlying ad object changes. - Implemented error handling for incorrect ad object types. - Updated documentation to reflect the new implementation and responsibilities of the widget.
1 parent a357a07 commit 3bf94e5

File tree

1 file changed

+67
-12
lines changed

1 file changed

+67
-12
lines changed

lib/ads/widgets/admob_native_ad_widget.dart

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,80 @@ import 'package:logging/logging.dart';
1212
/// It expects the `adObject` within the [app_ad_models.NativeAd] to be a fully
1313
/// loaded [admob.NativeAd] instance.
1414
/// {@endtemplate}
15-
class AdmobNativeAdWidget extends StatelessWidget {
15+
/// {@template admob_native_ad_widget}
16+
/// A widget that specifically renders a Google AdMob native ad.
17+
///
18+
/// This widget is responsible for taking the generic [app_ad_models.NativeAd]
19+
/// and rendering it using the `AdWidget` from the `google_mobile_ads` package.
20+
/// It expects the `adObject` within the [app_ad_models.NativeAd] to be a fully
21+
/// loaded [admob.NativeAd] instance.
22+
///
23+
/// This is a [StatefulWidget] to properly manage the lifecycle of the native
24+
/// ad object, ensuring it is disposed when the widget is removed from the tree
25+
/// or when the underlying ad object changes.
26+
/// {@endtemplate}
27+
class AdmobNativeAdWidget extends StatefulWidget {
1628
/// {@macro admob_native_ad_widget}
1729
const AdmobNativeAdWidget({required this.nativeAd, super.key});
1830

1931
/// The generic native ad model which contains the provider-specific ad object.
2032
final app_ad_models.NativeAd nativeAd;
2133

2234
@override
23-
Widget build(BuildContext context) {
24-
final adObject = nativeAd.adObject;
35+
State<AdmobNativeAdWidget> createState() => _AdmobNativeAdWidgetState();
36+
}
2537

26-
// Safely cast the generic ad object to the expected AdMob native ad type.
27-
if (adObject is! admob.NativeAd) {
28-
Logger('AdmobNativeAdWidget').severe(
38+
class _AdmobNativeAdWidgetState extends State<AdmobNativeAdWidget> {
39+
admob.NativeAd? _ad;
40+
final Logger _logger = Logger('AdmobNativeAdWidget');
41+
42+
@override
43+
void initState() {
44+
super.initState();
45+
_setAd();
46+
}
47+
48+
@override
49+
void didUpdateWidget(covariant AdmobNativeAdWidget oldWidget) {
50+
super.didUpdateWidget(oldWidget);
51+
// If the nativeAd object itself has changed (e.g., a new ad was loaded
52+
// for the same placeholder ID), dispose the old ad and set the new one.
53+
if (widget.nativeAd.id != oldWidget.nativeAd.id) {
54+
_ad?.dispose();
55+
_setAd();
56+
}
57+
}
58+
59+
@override
60+
void dispose() {
61+
// Dispose the native ad when the widget is removed from the tree.
62+
// This is crucial for releasing native resources and preventing crashes.
63+
_ad?.dispose();
64+
_logger.info('AdmobNativeAdWidget disposed and native ad released.');
65+
super.dispose();
66+
}
67+
68+
/// Sets the internal [_ad] object from the widget's [nativeAd].
69+
///
70+
/// This method ensures that the adObject is of the correct type and
71+
/// logs an error if it's not.
72+
void _setAd() {
73+
if (widget.nativeAd.adObject is admob.NativeAd) {
74+
_ad = widget.nativeAd.adObject as admob.NativeAd;
75+
} else {
76+
_ad = null; // Ensure _ad is null if the type is incorrect
77+
_logger.severe(
2978
'The provided ad object is not of type admob.NativeAd. '
30-
'Received: ${adObject.runtimeType}. Ad will not be displayed.',
79+
'Received: ${widget.nativeAd.adObject.runtimeType}. Ad will not be displayed.',
3180
);
81+
}
82+
}
83+
84+
@override
85+
Widget build(BuildContext context) {
86+
if (_ad == null) {
3287
// Return an empty widget if the ad object is not of the correct type
33-
// to prevent runtime errors.
88+
// or if it was explicitly set to null due to an error.
3489
return const SizedBox.shrink();
3590
}
3691

@@ -39,14 +94,14 @@ class AdmobNativeAdWidget extends StatelessWidget {
3994
// We wrap it in a SizedBox to provide explicit height constraints,
4095
// which is crucial for platform views (like native ads) within scrollable
4196
// lists to prevent "unbounded height" errors.
42-
final adHeight = switch (nativeAd.templateType) {
43-
app_ad_models.NativeAdTemplateType.small => 120, // Example height for small template
44-
app_ad_models.NativeAdTemplateType.medium => 340, // Example height for medium template
97+
final adHeight = switch (widget.nativeAd.templateType) {
98+
app_ad_models.NativeAdTemplateType.small => 120,
99+
app_ad_models.NativeAdTemplateType.medium => 340,
45100
};
46101

47102
return SizedBox(
48103
height: adHeight.toDouble(),
49-
child: admob.AdWidget(ad: adObject),
104+
child: admob.AdWidget(ad: _ad!),
50105
);
51106
}
52107
}

0 commit comments

Comments
 (0)