Skip to content

Commit e04b537

Browse files
CopilotYBTopaz8
andcommitted
Add proper cancellation and error handling to background cover art caching
- Add CancellationTokenSource field to manage background operations - Wrap fire-and-forget Task.Run with try-catch for error handling - Pass cancellation token through EnsureAllCoverArtCachedForSongsAsync - Reduce parallelism on Android (4 vs 8 on Windows) to lower memory pressure - Add cancellation checks in the processing loop - Dispose cancellation token properly in Dispose method This prevents Android crashes caused by unhandled exceptions and excessive memory usage during background cover image cache scanning. Co-authored-by: YBTopaz8 <41630728+YBTopaz8@users.noreply.github.com>
1 parent dc8da05 commit e04b537

File tree

1 file changed

+36
-9
lines changed

1 file changed

+36
-9
lines changed

Dimmer/Dimmer/ViewModel/BaseViewModel.cs

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -678,16 +678,28 @@ await lastFMRealm.WriteAsync(() =>
678678
var duration = endTime - startTime;
679679
Debug.WriteLine(
680680
$"{DateTime.Now}: Finished InitializeAllVMCoreComponentsAsync in {duration.TotalSeconds} seconds.");
681+
682+
// Initialize background caching with proper error handling and cancellation support
683+
_backgroundCachingCts = new CancellationTokenSource();
681684
_ = Task.Run(async () =>
682685
{
683-
await OnAppOpening();
684-
await HeavierBackGroundLoadings(FolderPaths);
686+
try
687+
{
688+
await OnAppOpening();
689+
await HeavierBackGroundLoadings(FolderPaths);
685690

686-
await Task.Delay(3000);
687-
await EnsureAllCoverArtCachedForSongsAsync();
688-
CancellationTokenSource cts = new();
689-
//await LoadAllSongsLyricsFromOnlineAsync(cts);
690-
});
691+
await Task.Delay(3000, _backgroundCachingCts.Token);
692+
await EnsureAllCoverArtCachedForSongsAsync(_backgroundCachingCts.Token);
693+
}
694+
catch (OperationCanceledException)
695+
{
696+
_logger.LogInformation("Background cover art caching was cancelled.");
697+
}
698+
catch (Exception ex)
699+
{
700+
_logger.LogError(ex, "Error during background initialization and cover art caching.");
701+
}
702+
}, _backgroundCachingCts.Token);
691703

692704
IsInitialized = true;
693705
return;
@@ -1389,6 +1401,9 @@ public async Task PlayPlaylist(PlaylistModelView? playlist)
13891401
public IDimmerAudioService AudioService => _audioService;
13901402
private ILibraryScannerService libScannerService;
13911403

1404+
// Cancellation token for background cover art caching to prevent memory issues on Android
1405+
private CancellationTokenSource? _backgroundCachingCts;
1406+
13921407
public CompositeDisposable SubsManager => _subsManager;
13931408
private readonly CompositeDisposable _subsManager = new CompositeDisposable();
13941409

@@ -2334,7 +2349,7 @@ public async Task LoadAndCacheCoverArtAsync(SongModelView song)
23342349
[ObservableProperty]
23352350
public partial Progress<(int current, int total, SongModelView song)> ProgressCoverArtLoad { get; set; }
23362351
[RelayCommand]
2337-
public async Task EnsureAllCoverArtCachedForSongsAsync()
2352+
public async Task EnsureAllCoverArtCachedForSongsAsync(CancellationToken cancellationToken = default)
23382353
{
23392354
IsAppLoadingCovers = true;
23402355
// 1. Get the TOTAL count safely using a short-lived Realm instance
@@ -2354,9 +2369,13 @@ public async Task EnsureAllCoverArtCachedForSongsAsync()
23542369

23552370
int processedCount = 0;
23562371

2372+
// Use lower parallelism on Android to reduce memory pressure
2373+
var maxParallelism = DeviceInfo.Platform == DevicePlatform.Android ? 4 : 8;
2374+
23572375
var parallelOptions = new ParallelOptions
23582376
{
2359-
MaxDegreeOfParallelism = 8
2377+
MaxDegreeOfParallelism = maxParallelism,
2378+
CancellationToken = cancellationToken
23602379
};
23612380
var batches = songsToProcessIds.Chunk(20);
23622381

@@ -2377,6 +2396,9 @@ await Parallel.ForEachAsync(batches, parallelOptions, async (batchOfIds, ct) =>
23772396
}
23782397
foreach (var songView in songsInBatch)
23792398
{
2399+
// Check cancellation before processing each song
2400+
ct.ThrowIfCancellationRequested();
2401+
23802402
bool needsProcessing = string.IsNullOrEmpty(songView.CoverImagePath)
23812403
|| !TaggingUtils.FileExists(songView.CoverImagePath);
23822404

@@ -5135,6 +5157,11 @@ protected virtual void Dispose(bool disposing)
51355157

51365158
if (disposing)
51375159
{
5160+
// Cancel background caching operations
5161+
_backgroundCachingCts?.Cancel();
5162+
_backgroundCachingCts?.Dispose();
5163+
_backgroundCachingCts = null;
5164+
51385165
_realmSubscription?.Dispose();
51395166
_playEventSource.Dispose();
51405167
realm?.Dispose();

0 commit comments

Comments
 (0)