diff options
| author | 2023-12-10 20:54:00 -0500 | |
|---|---|---|
| committer | 2023-12-12 17:25:37 -0500 | |
| commit | f9d48271029142695d29e065c3449c57ea7c7ded (patch) | |
| tree | ce206083ab074d8dbbc1cb66791a625003cba61c /src/android | |
| parent | android: Collect latest information for games list (diff) | |
| download | yuzu-f9d48271029142695d29e065c3449c57ea7c7ded.tar.gz yuzu-f9d48271029142695d29e065c3449c57ea7c7ded.tar.xz yuzu-f9d48271029142695d29e065c3449c57ea7c7ded.zip | |
android: Fix games list loading thread safety
Previously we relied on a stateflow for reloading state. Now we use an atomic boolean.
Diffstat (limited to 'src/android')
| -rw-r--r-- | src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt | 74 |
1 files changed, 38 insertions, 36 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt index eaec09b24..d19f20dc2 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt | |||
| @@ -20,8 +20,8 @@ import kotlinx.serialization.json.Json | |||
| 20 | import org.yuzu.yuzu_emu.NativeLibrary | 20 | import org.yuzu.yuzu_emu.NativeLibrary |
| 21 | import org.yuzu.yuzu_emu.YuzuApplication | 21 | import org.yuzu.yuzu_emu.YuzuApplication |
| 22 | import org.yuzu.yuzu_emu.utils.GameHelper | 22 | import org.yuzu.yuzu_emu.utils.GameHelper |
| 23 | import org.yuzu.yuzu_emu.utils.GameMetadata | ||
| 24 | import org.yuzu.yuzu_emu.utils.NativeConfig | 23 | import org.yuzu.yuzu_emu.utils.NativeConfig |
| 24 | import java.util.concurrent.atomic.AtomicBoolean | ||
| 25 | 25 | ||
| 26 | class GamesViewModel : ViewModel() { | 26 | class GamesViewModel : ViewModel() { |
| 27 | val games: StateFlow<List<Game>> get() = _games | 27 | val games: StateFlow<List<Game>> get() = _games |
| @@ -33,6 +33,8 @@ class GamesViewModel : ViewModel() { | |||
| 33 | val isReloading: StateFlow<Boolean> get() = _isReloading | 33 | val isReloading: StateFlow<Boolean> get() = _isReloading |
| 34 | private val _isReloading = MutableStateFlow(false) | 34 | private val _isReloading = MutableStateFlow(false) |
| 35 | 35 | ||
| 36 | private val reloading = AtomicBoolean(false) | ||
| 37 | |||
| 36 | val shouldSwapData: StateFlow<Boolean> get() = _shouldSwapData | 38 | val shouldSwapData: StateFlow<Boolean> get() = _shouldSwapData |
| 37 | private val _shouldSwapData = MutableStateFlow(false) | 39 | private val _shouldSwapData = MutableStateFlow(false) |
| 38 | 40 | ||
| @@ -49,38 +51,8 @@ class GamesViewModel : ViewModel() { | |||
| 49 | // Ensure keys are loaded so that ROM metadata can be decrypted. | 51 | // Ensure keys are loaded so that ROM metadata can be decrypted. |
| 50 | NativeLibrary.reloadKeys() | 52 | NativeLibrary.reloadKeys() |
| 51 | 53 | ||
| 52 | // Retrieve list of cached games | 54 | getGameDirs() |
| 53 | val storedGames = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | 55 | reloadGames(directoriesChanged = false, firstStartup = true) |
| 54 | .getStringSet(GameHelper.KEY_GAMES, emptySet()) | ||
| 55 | |||
| 56 | viewModelScope.launch { | ||
| 57 | withContext(Dispatchers.IO) { | ||
| 58 | getGameDirs() | ||
| 59 | if (storedGames!!.isNotEmpty()) { | ||
| 60 | val deserializedGames = mutableSetOf<Game>() | ||
| 61 | storedGames.forEach { | ||
| 62 | val game: Game | ||
| 63 | try { | ||
| 64 | game = Json.decodeFromString(it) | ||
| 65 | } catch (e: Exception) { | ||
| 66 | // We don't care about any errors related to parsing the game cache | ||
| 67 | return@forEach | ||
| 68 | } | ||
| 69 | |||
| 70 | val gameExists = | ||
| 71 | DocumentFile.fromSingleUri( | ||
| 72 | YuzuApplication.appContext, | ||
| 73 | Uri.parse(game.path) | ||
| 74 | )?.exists() | ||
| 75 | if (gameExists == true) { | ||
| 76 | deserializedGames.add(game) | ||
| 77 | } | ||
| 78 | } | ||
| 79 | setGames(deserializedGames.toList()) | ||
| 80 | } | ||
| 81 | reloadGames(false) | ||
| 82 | } | ||
| 83 | } | ||
| 84 | } | 56 | } |
| 85 | 57 | ||
| 86 | fun setGames(games: List<Game>) { | 58 | fun setGames(games: List<Game>) { |
| @@ -110,16 +82,46 @@ class GamesViewModel : ViewModel() { | |||
| 110 | _searchFocused.value = searchFocused | 82 | _searchFocused.value = searchFocused |
| 111 | } | 83 | } |
| 112 | 84 | ||
| 113 | fun reloadGames(directoriesChanged: Boolean) { | 85 | fun reloadGames(directoriesChanged: Boolean, firstStartup: Boolean = false) { |
| 114 | if (isReloading.value) { | 86 | if (reloading.get()) { |
| 115 | return | 87 | return |
| 116 | } | 88 | } |
| 89 | reloading.set(true) | ||
| 117 | _isReloading.value = true | 90 | _isReloading.value = true |
| 118 | 91 | ||
| 119 | viewModelScope.launch { | 92 | viewModelScope.launch { |
| 120 | withContext(Dispatchers.IO) { | 93 | withContext(Dispatchers.IO) { |
| 121 | GameMetadata.resetMetadata() | 94 | if (firstStartup) { |
| 95 | // Retrieve list of cached games | ||
| 96 | val storedGames = | ||
| 97 | PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||
| 98 | .getStringSet(GameHelper.KEY_GAMES, emptySet()) | ||
| 99 | if (storedGames!!.isNotEmpty()) { | ||
| 100 | val deserializedGames = mutableSetOf<Game>() | ||
| 101 | storedGames.forEach { | ||
| 102 | val game: Game | ||
| 103 | try { | ||
| 104 | game = Json.decodeFromString(it) | ||
| 105 | } catch (e: Exception) { | ||
| 106 | // We don't care about any errors related to parsing the game cache | ||
| 107 | return@forEach | ||
| 108 | } | ||
| 109 | |||
| 110 | val gameExists = | ||
| 111 | DocumentFile.fromSingleUri( | ||
| 112 | YuzuApplication.appContext, | ||
| 113 | Uri.parse(game.path) | ||
| 114 | )?.exists() | ||
| 115 | if (gameExists == true) { | ||
| 116 | deserializedGames.add(game) | ||
| 117 | } | ||
| 118 | } | ||
| 119 | setGames(deserializedGames.toList()) | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 122 | setGames(GameHelper.getGames()) | 123 | setGames(GameHelper.getGames()) |
| 124 | reloading.set(false) | ||
| 123 | _isReloading.value = false | 125 | _isReloading.value = false |
| 124 | 126 | ||
| 125 | if (directoriesChanged) { | 127 | if (directoriesChanged) { |