Skip to content

Commit 0360028

Browse files
fix improved based on the suggestion
1 parent 027242a commit 0360028

1 file changed

Lines changed: 35 additions & 9 deletions

File tree

src/Essentials/src/Connectivity/Connectivity.ios.tvos.macos.reachability.cs

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ class ReachabilityListener : IDisposable
109109
const int ConnectionStatusChangeDelayMs = 100;
110110

111111
NWPathMonitor pathMonitor;
112+
CancellationTokenSource cts = new CancellationTokenSource();
113+
int pendingCallbacks;
112114

113115
internal ReachabilityListener()
114116
{
@@ -130,6 +132,10 @@ internal ReachabilityListener()
130132

131133
internal void Dispose()
132134
{
135+
cts?.Cancel();
136+
cts?.Dispose();
137+
cts = null;
138+
133139
if (pathMonitor != null)
134140
{
135141
pathMonitor.SnapshotHandler = null;
@@ -170,25 +176,45 @@ void OnRestrictedStateChanged(CTCellularDataRestrictedState state)
170176

171177
async void OnChange(NetworkReachabilityFlags flags)
172178
{
173-
// This function waits up to 1 second, checking the device’s network status every 100 milliseconds.
179+
// Deduplicate: both watchers may fire for the same network change.
180+
// Only the first callback runs the polling loop; subsequent ones are no-ops.
181+
if (Interlocked.Increment(ref pendingCallbacks) > 1)
182+
return;
183+
184+
var token = cts?.Token ?? default;
185+
if (token.IsCancellationRequested)
186+
return;
187+
188+
// This function waits up to 1 second, checking the device's network status every 100 milliseconds.
174189
// If the network status changes, it immediately triggers the ReachabilityChanged event.
175190
var initialAccess = Connectivity.NetworkAccess;
176191
const int pollingIntervalMs = 100;
177192
const int maxWaitTimeMs = 1000;
178193
int elapsedTime = 0;
179194

180-
while (elapsedTime < maxWaitTimeMs)
195+
try
181196
{
182-
await Task.Delay(pollingIntervalMs);
183-
elapsedTime += pollingIntervalMs;
184-
var currentAccess = Connectivity.NetworkAccess;
185-
if (currentAccess != initialAccess)
197+
while (elapsedTime < maxWaitTimeMs)
186198
{
187-
ReachabilityChanged?.Invoke();
188-
return;
199+
await Task.Delay(pollingIntervalMs, token);
200+
elapsedTime += pollingIntervalMs;
201+
var currentAccess = Connectivity.NetworkAccess;
202+
if (currentAccess != initialAccess)
203+
{
204+
ReachabilityChanged?.Invoke();
205+
return;
206+
}
189207
}
208+
ReachabilityChanged?.Invoke();
209+
}
210+
catch (OperationCanceledException)
211+
{
212+
// Listener was disposed during polling, don't fire event
213+
}
214+
finally
215+
{
216+
Interlocked.Exchange(ref pendingCallbacks, 0);
190217
}
191-
ReachabilityChanged?.Invoke();
192218
}
193219
}
194220
}

0 commit comments

Comments
 (0)