Skip to content

Commit 1a563a3

Browse files
david-allison7se7en72025
authored andcommitted
fix(deck-picker) freeze after theme changes
Fixes deadlocking in DeckPicker when changing themes by adding buffers to MutableSharedFlow instances. The issue occurred because: 1. DeckPicker uses launchCollectionInLifecycleScope which only collects flows when activity is RESUMED 2. During theme changes, the activity is recreated and temporarily not in RESUMED state 3. emit() calls on MutableSharedFlow without buffers would suspend indefinitely when no collectors were active 4. This caused the app to freeze/hang after theme changes Solution: - Added extraBufferCapacity = 1 to all MutableSharedFlow instances in DeckPickerViewModel - This allows emit() calls to succeed even when no collectors are active - The buffered events will be processed when collectors resume Fixes 19512 Co-authored-by: raiyyan <[email protected]>
1 parent 46cc209 commit 1a563a3

File tree

1 file changed

+9
-9
lines changed

1 file changed

+9
-9
lines changed

AnkiDroid/src/main/java/com/ichi2/anki/deckpicker/DeckPickerViewModel.kt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ class DeckPickerViewModel :
105105
/**
106106
* Used if the Deck Due Tree is mutated
107107
*/
108-
private val flowOfRefreshDeckList = MutableSharedFlow<Unit>()
108+
private val flowOfRefreshDeckList = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
109109

110110
val flowOfDeckList =
111111
combine(
@@ -130,16 +130,16 @@ class DeckPickerViewModel :
130130
* @see deleteDeck
131131
* @see DeckDeletionResult
132132
*/
133-
val deckDeletedNotification = MutableSharedFlow<DeckDeletionResult>()
134-
val emptyCardsNotification = MutableSharedFlow<EmptyCardsResult>()
135-
val flowOfDestination = MutableSharedFlow<Destination>()
136-
override val onError = MutableSharedFlow<String>()
133+
val deckDeletedNotification = MutableSharedFlow<DeckDeletionResult>(extraBufferCapacity = 1)
134+
val emptyCardsNotification = MutableSharedFlow<EmptyCardsResult>(extraBufferCapacity = 1)
135+
val flowOfDestination = MutableSharedFlow<Destination>(extraBufferCapacity = 1)
136+
override val onError = MutableSharedFlow<String>(extraBufferCapacity = 1)
137137

138138
/**
139139
* A notification that the study counts have changed
140140
*/
141141
// TODO: most of the recalculation should be moved inside the ViewModel
142-
val flowOfDeckCountsChanged = MutableSharedFlow<Unit>()
142+
val flowOfDeckCountsChanged = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
143143

144144
var loadDeckCounts: Job? = null
145145
private set
@@ -150,9 +150,9 @@ class DeckPickerViewModel :
150150
*/
151151
private var schedulerUpgradeDialogShownForVersion: Long? = null
152152

153-
val flowOfPromptUserToUpdateScheduler = MutableSharedFlow<Unit>()
153+
val flowOfPromptUserToUpdateScheduler = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
154154

155-
val flowOfUndoUpdated = MutableSharedFlow<Unit>()
155+
val flowOfUndoUpdated = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
156156

157157
val flowOfCollectionHasNoCards = MutableStateFlow(true)
158158

@@ -180,7 +180,7 @@ class DeckPickerViewModel :
180180

181181
// HACK: dismiss a legacy progress bar
182182
// TODO: Replace with better progress handling for first load/corrupt collections
183-
val flowOfDecksReloaded = MutableSharedFlow<Unit>()
183+
val flowOfDecksReloaded = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
184184

185185
/**
186186
* Deletes the provided deck, child decks. and all cards inside.

0 commit comments

Comments
 (0)