Skip to content

Commit 8a7333b

Browse files
committed
Dispose view models correctly
1 parent ac1aa54 commit 8a7333b

File tree

7 files changed

+57
-27
lines changed

7 files changed

+57
-27
lines changed

src/Bible.Alarm/ViewModels/Bible/BibleSelectionViewModel.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@
1414

1515
namespace Bible.Alarm.ViewModels.Bible;
1616

17-
public class BibleSelectionViewModel : ObservableObject, IListViewModel
17+
public class BibleSelectionViewModel : ObservableObject, IListViewModel, IDisposable
1818
{
1919
private readonly MediaService _mediaService;
2020
private readonly IState<ApplicationState> _state;
2121

2222
private BibleReadingSchedule _current;
2323
private BibleReadingSchedule _tentative;
24+
private bool _initComplete;
2425

2526
public ICommand BackCommand { get; set; }
2627
public ICommand BookSelectionCommand { get; set; }
@@ -92,16 +93,17 @@ public BibleSelectionViewModel(MediaService mediaService, IServiceScopeFactory s
9293

9394
void OnBibleReadingInitialized(object o, EventArgs eventArgs)
9495
{
96+
if (_initComplete) return;
9597
var stateValue = _state.Value;
9698
if (stateValue.CurrentBibleReadingSchedule == null || stateValue.TentativeBibleReadingSchedule == null) return;
9799
_current = stateValue.CurrentBibleReadingSchedule;
98100
_tentative = stateValue.TentativeBibleReadingSchedule;
101+
_initComplete = true;
99102
Task.Run(async () =>
100103
{
101104
await Initialize(_tentative.LanguageCode);
102105
await MainThread.InvokeOnMainThreadAsync(() => IsBusy = false);
103106
});
104-
_state.StateChanged -= OnBibleReadingInitialized;
105107
}
106108

107109
void OnBibleReadingChanged(object sender, EventArgs e)
@@ -244,4 +246,10 @@ private async Task PopulateTranslations(string languageCode)
244246

245247
Translations = translationVMs;
246248
}
249+
250+
public void Dispose()
251+
{
252+
_state.StateChanged -= OnBibleReadingInitialized;
253+
_state.StateChanged -= OnBibleReadingChanged;
254+
}
247255
}

src/Bible.Alarm/ViewModels/Bible/BookSelectionViewModel.cs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ public class BookSelectionViewModel : ObservableObject, IDisposable
2121

2222
private readonly MediaService _mediaService;
2323
private readonly IState<ApplicationState> _state;
24-
private EventHandler _onBibleReadingChanged;
25-
private EventHandler _onBibleReadingInitialized;
24+
private bool _initComplete;
2625

2726
public ICommand BackCommand { get; set; }
2827
public ICommand ChapterSelectionCommand { get; set; }
@@ -77,34 +76,25 @@ void OnBibleReadingChanged(object sender, EventArgs e)
7776

7877
void OnBibleReadingInitialized(object o, EventArgs eventArgs)
7978
{
79+
if (_initComplete) return;
8080
var stateValue = _state.Value;
8181
if (stateValue.CurrentBibleReadingSchedule == null || stateValue.TentativeBibleReadingSchedule == null) return;
8282
_current = stateValue.CurrentBibleReadingSchedule;
8383
_tentative = stateValue.TentativeBibleReadingSchedule;
84+
_initComplete = true;
8485
Task.Run(async () =>
8586
{
8687
await MainThread.InvokeOnMainThreadAsync(() => IsBusy = true);
8788
await Initialize(_tentative.LanguageCode, _tentative.PublicationCode);
8889
await MainThread.InvokeOnMainThreadAsync(() => IsBusy = false);
8990
});
90-
91-
if (_onBibleReadingInitialized == null) return;
92-
_state.StateChanged -= _onBibleReadingInitialized;
93-
_onBibleReadingInitialized = null;
9491
}
9592
}
9693

9794
public void Dispose()
9895
{
99-
if (_onBibleReadingChanged != null)
100-
{
101-
_state.StateChanged -= _onBibleReadingChanged;
102-
_onBibleReadingChanged = null;
103-
}
104-
105-
if (_onBibleReadingInitialized == null) return;
106-
_state.StateChanged -= _onBibleReadingInitialized;
107-
_onBibleReadingInitialized = null;
96+
_state.StateChanged -= OnBibleReadingChanged;
97+
_state.StateChanged -= OnBibleReadingInitialized;
10898
}
10999

110100
private void SetSelectedBook()

src/Bible.Alarm/ViewModels/Bible/ChapterSelectionViewModel.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public class ChapterSelectionViewModel : ObservableObject, IDisposable
2929
private readonly IMediaCacheService _cacheService;
3030
private readonly IDownloadService _downloadService;
3131
private readonly IState<ApplicationState> _state;
32+
private bool _initComplete;
3233

3334
private readonly Dictionary<BibleChapterListViewItemModel, PropertyChangedEventHandler> _propertyChangedHandlers = [];
3435

@@ -86,16 +87,17 @@ public ChapterSelectionViewModel(
8687

8788
void OnBibleReadingInitialized(object o, EventArgs eventArgs)
8889
{
90+
if (_initComplete) return;
8991
var stateValue = _state.Value;
9092
if (stateValue.CurrentBibleReadingSchedule == null || stateValue.TentativeBibleReadingSchedule == null) return;
9193
_current = stateValue.CurrentBibleReadingSchedule;
9294
_tentative = stateValue.TentativeBibleReadingSchedule;
95+
_initComplete = true;
9396
Task.Run(async () =>
9497
{
9598
await Initialize(_tentative.LanguageCode, _tentative.PublicationCode, _tentative.BookNumber);
9699
await MainThread.InvokeOnMainThreadAsync(() => IsBusy = false);
97100
});
98-
_state.StateChanged -= OnBibleReadingInitialized;
99101
}
100102
}
101103

@@ -323,11 +325,15 @@ await MainThread.InvokeOnMainThreadAsync(() =>
323325

324326
public void Dispose()
325327
{
328+
_state.StateChanged -= OnBibleReadingInitialized;
326329
_playService.OnStopped -= OnPlayServiceStopped;
327330

328-
foreach (var chapter in Chapters)
331+
if (Chapters != null)
329332
{
330-
UnsubscribeFromChapterEvents(chapter);
333+
foreach (var chapter in Chapters)
334+
{
335+
UnsubscribeFromChapterEvents(chapter);
336+
}
331337
}
332338

333339
_propertyChangedHandlers.Clear();

src/Bible.Alarm/ViewModels/Music/MusicSelectionViewModel.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
namespace Bible.Alarm.ViewModels.Music;
1515

16-
public class MusicSelectionViewModel : ObservableObject
16+
public class MusicSelectionViewModel : ObservableObject, IDisposable
1717
{
1818
private AlarmMusic _current;
1919

@@ -123,6 +123,11 @@ public MusicTypeListItemViewModel SelectedMusicType
123123
get => _selectedMusicType;
124124
set => SetProperty(ref _selectedMusicType, value);
125125
}
126+
127+
public void Dispose()
128+
{
129+
_state.StateChanged -= OnStateOnStateChanged;
130+
}
126131
}
127132

128133
public class MusicTypeListItemViewModel : ObservableObject, IComparable

src/Bible.Alarm/ViewModels/Music/SongBookSelectionViewModel.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515

1616
namespace Bible.Alarm.ViewModels.Music;
1717

18-
public class SongBookSelectionViewModel : ObservableObject, IListViewModel
18+
public class SongBookSelectionViewModel : ObservableObject, IListViewModel, IDisposable
1919
{
2020
private readonly MediaService _mediaService;
2121
private readonly IState<ApplicationState> _state;
2222

2323
private AlarmMusic _current;
2424
private AlarmMusic _tentative;
25+
private bool _initComplete;
2526

2627
public SongBookSelectionViewModel(MediaService mediaService, IServiceScopeFactory scopeFactory, INavigationService navigationService)
2728
{
@@ -50,16 +51,17 @@ void OnMusicChanged(object sender, EventArgs e)
5051

5152
void OnMusicInitialized(object o, EventArgs eventArgs)
5253
{
54+
if (_initComplete) return;
5355
var stateValue = _state.Value;
5456
if (stateValue.CurrentMusic == null || stateValue.TentativeMusic == null) return;
5557
_current = stateValue.CurrentMusic;
5658
_tentative = stateValue.TentativeMusic;
59+
_initComplete = true;
5760
Task.Run(async () =>
5861
{
5962
await Initialize();
6063
await MainThread.InvokeOnMainThreadAsync(() => IsBusy = false);
6164
});
62-
_state.StateChanged -= OnMusicInitialized;
6365
}
6466

6567
_state.StateChanged += OnMusicInitialized;
@@ -261,4 +263,10 @@ private async Task PopulateSongBooks(string languageCode)
261263

262264
SongBooks = songBookVMs;
263265
}
266+
267+
public void Dispose()
268+
{
269+
_state.StateChanged -= OnMusicInitialized;
270+
_state.StateChanged -= OnMusicChanged;
271+
}
264272
}

src/Bible.Alarm/ViewModels/Music/TrackSelectionViewModel.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public class TrackSelectionViewModel : ObservableObject, IDisposable
3333
private AlarmMusic _current;
3434
private AlarmMusic _tentative;
3535
private bool _initialized;
36+
private bool _initComplete;
3637

3738
private readonly Dictionary<MusicTrackListViewItemModel, PropertyChangedEventHandler> _propertyChangedHandlers = [];
3839

@@ -103,6 +104,7 @@ public TrackSelectionViewModel(
103104

104105
void OnMusicInitialized(object o, EventArgs eventArgs)
105106
{
107+
if (_initComplete) return;
106108
if (_initialized) return;
107109
var stateValue = _state.Value;
108110
// For track selection, we only need TentativeMusic to initialize
@@ -112,13 +114,13 @@ void OnMusicInitialized(object o, EventArgs eventArgs)
112114
// Use TentativeMusic as CurrentMusic if CurrentMusic is null
113115
_current = stateValue.CurrentMusic ?? stateValue.TentativeMusic;
114116
_initialized = true;
117+
_initComplete = true;
115118
Task.Run(async () =>
116119
{
117120
await MainThread.InvokeOnMainThreadAsync(() => IsBusy = true);
118121
await Initialize(_tentative.LanguageCode, _tentative.PublicationCode);
119122
await MainThread.InvokeOnMainThreadAsync(() => IsBusy = false);
120123
});
121-
_state.StateChanged -= OnMusicInitialized;
122124
}
123125
}
124126

@@ -372,11 +374,15 @@ await MainThread.InvokeOnMainThreadAsync(() =>
372374

373375
public void Dispose()
374376
{
377+
_state.StateChanged -= OnMusicInitialized;
375378
_playService.OnStopped -= OnPlayServiceStopped;
376379

377-
foreach (var track in Tracks)
380+
if (Tracks != null)
378381
{
379-
UnsubscribeFromTrackEvents(track);
382+
foreach (var track in Tracks)
383+
{
384+
UnsubscribeFromTrackEvents(track);
385+
}
380386
}
381387

382388
_propertyChangedHandlers.Clear();

src/Bible.Alarm/ViewModels/ScheduleViewModel.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
namespace Bible.Alarm.ViewModels;
2323

24-
public class ScheduleViewModel : ObservableObject
24+
public class ScheduleViewModel : ObservableObject, IDisposable
2525
{
2626
private readonly ILogger _logger;
2727

@@ -678,4 +678,11 @@ await MainThread.InvokeOnMainThreadAsync(() =>
678678
}
679679
});
680680
}
681+
682+
public void Dispose()
683+
{
684+
_state.StateChanged -= OnCurrentScheduleChanged;
685+
_state.StateChanged -= OnMusicChanged;
686+
_state.StateChanged -= OnBibleReadingChanged;
687+
}
681688
}

0 commit comments

Comments
 (0)