1+ import 'dart:async' ;
2+
13import 'package:core/core.dart' ;
24import 'package:flutter/material.dart' ;
35import 'package:flutter_news_app_mobile_client_full_source_code/ads/ad_cache_service.dart' ;
@@ -55,18 +57,36 @@ class _AdLoaderWidgetState extends State<AdLoaderWidget> {
5557 final Logger _logger = Logger ('AdLoaderWidget' );
5658 final AdCacheService _adCacheService = AdCacheService ();
5759
60+ // Completer to manage the lifecycle of the ad loading future.
61+ // This helps in cancelling pending operations if the widget is disposed.
62+ Completer <void >? _loadAdCompleter;
63+
5864 @override
5965 void initState () {
6066 super .initState ();
6167 _loadAd ();
6268 }
6369
70+ @override
71+ void dispose () {
72+ // Cancel any pending ad loading operation when the widget is disposed.
73+ // This prevents `setState()` calls on a disposed widget.
74+ _loadAdCompleter? .completeError (
75+ StateError ('Ad loading cancelled: Widget disposed.' ),
76+ );
77+ _loadAdCompleter = null ;
78+ super .dispose ();
79+ }
80+
6481 /// Loads the native ad for this slot.
6582 ///
6683 /// This method first checks the [AdCacheService] for a pre-loaded ad.
6784 /// If found, it uses the cached ad. Otherwise, it requests a new ad
6885 /// from the [AdService] and stores it in the cache upon success.
6986 Future <void > _loadAd () async {
87+ // Initialize a new completer for this loading operation.
88+ _loadAdCompleter = Completer <void >();
89+
7090 // Ensure the widget is still mounted before calling setState.
7191 // This prevents the "setState() called after dispose()" error
7292 // if the widget is removed from the tree while the async operation
@@ -89,6 +109,7 @@ class _AdLoaderWidgetState extends State<AdLoaderWidget> {
89109 _loadedAd = cachedAd;
90110 _isLoading = false ;
91111 });
112+ _loadAdCompleter? .complete (); // Complete the completer on success
92113 return ;
93114 }
94115
@@ -117,6 +138,7 @@ class _AdLoaderWidgetState extends State<AdLoaderWidget> {
117138 _loadedAd = adFeedItem.nativeAd;
118139 _isLoading = false ;
119140 });
141+ _loadAdCompleter? .complete (); // Complete the completer on success
120142 } else {
121143 _logger.warning (
122144 'Failed to load ad for placeholder ID: ${widget .adPlaceholder .id }. No ad returned.' ,
@@ -127,6 +149,9 @@ class _AdLoaderWidgetState extends State<AdLoaderWidget> {
127149 _hasError = true ;
128150 _isLoading = false ;
129151 });
152+ _loadAdCompleter? .completeError (
153+ StateError ('Failed to load ad: No ad returned.' ),
154+ ); // Complete with error
130155 }
131156 } catch (e, s) {
132157 _logger.severe (
@@ -140,6 +165,7 @@ class _AdLoaderWidgetState extends State<AdLoaderWidget> {
140165 _hasError = true ;
141166 _isLoading = false ;
142167 });
168+ _loadAdCompleter? .completeError (e); // Complete with error
143169 }
144170 }
145171
0 commit comments