Просмотр исходного кода

android: Fix games list loading thread safety

Previously we relied on a stateflow for reloading state. Now we use an atomic boolean.
t895 2 лет назад
Родитель
Сommit
f9d4827102
1 измененных файлов с 38 добавлено и 36 удалено
  1. 38 36
      src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt

+ 38 - 36
src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt

@@ -20,8 +20,8 @@ import kotlinx.serialization.json.Json
 import org.yuzu.yuzu_emu.NativeLibrary
 import org.yuzu.yuzu_emu.NativeLibrary
 import org.yuzu.yuzu_emu.YuzuApplication
 import org.yuzu.yuzu_emu.YuzuApplication
 import org.yuzu.yuzu_emu.utils.GameHelper
 import org.yuzu.yuzu_emu.utils.GameHelper
-import org.yuzu.yuzu_emu.utils.GameMetadata
 import org.yuzu.yuzu_emu.utils.NativeConfig
 import org.yuzu.yuzu_emu.utils.NativeConfig
+import java.util.concurrent.atomic.AtomicBoolean
 
 
 class GamesViewModel : ViewModel() {
 class GamesViewModel : ViewModel() {
     val games: StateFlow<List<Game>> get() = _games
     val games: StateFlow<List<Game>> get() = _games
@@ -33,6 +33,8 @@ class GamesViewModel : ViewModel() {
     val isReloading: StateFlow<Boolean> get() = _isReloading
     val isReloading: StateFlow<Boolean> get() = _isReloading
     private val _isReloading = MutableStateFlow(false)
     private val _isReloading = MutableStateFlow(false)
 
 
+    private val reloading = AtomicBoolean(false)
+
     val shouldSwapData: StateFlow<Boolean> get() = _shouldSwapData
     val shouldSwapData: StateFlow<Boolean> get() = _shouldSwapData
     private val _shouldSwapData = MutableStateFlow(false)
     private val _shouldSwapData = MutableStateFlow(false)
 
 
@@ -49,38 +51,8 @@ class GamesViewModel : ViewModel() {
         // Ensure keys are loaded so that ROM metadata can be decrypted.
         // Ensure keys are loaded so that ROM metadata can be decrypted.
         NativeLibrary.reloadKeys()
         NativeLibrary.reloadKeys()
 
 
-        // Retrieve list of cached games
-        val storedGames = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
-            .getStringSet(GameHelper.KEY_GAMES, emptySet())
-
-        viewModelScope.launch {
-            withContext(Dispatchers.IO) {
-                getGameDirs()
-                if (storedGames!!.isNotEmpty()) {
-                    val deserializedGames = mutableSetOf<Game>()
-                    storedGames.forEach {
-                        val game: Game
-                        try {
-                            game = Json.decodeFromString(it)
-                        } catch (e: Exception) {
-                            // We don't care about any errors related to parsing the game cache
-                            return@forEach
-                        }
-
-                        val gameExists =
-                            DocumentFile.fromSingleUri(
-                                YuzuApplication.appContext,
-                                Uri.parse(game.path)
-                            )?.exists()
-                        if (gameExists == true) {
-                            deserializedGames.add(game)
-                        }
-                    }
-                    setGames(deserializedGames.toList())
-                }
-                reloadGames(false)
-            }
-        }
+        getGameDirs()
+        reloadGames(directoriesChanged = false, firstStartup = true)
     }
     }
 
 
     fun setGames(games: List<Game>) {
     fun setGames(games: List<Game>) {
@@ -110,16 +82,46 @@ class GamesViewModel : ViewModel() {
         _searchFocused.value = searchFocused
         _searchFocused.value = searchFocused
     }
     }
 
 
-    fun reloadGames(directoriesChanged: Boolean) {
-        if (isReloading.value) {
+    fun reloadGames(directoriesChanged: Boolean, firstStartup: Boolean = false) {
+        if (reloading.get()) {
             return
             return
         }
         }
+        reloading.set(true)
         _isReloading.value = true
         _isReloading.value = true
 
 
         viewModelScope.launch {
         viewModelScope.launch {
             withContext(Dispatchers.IO) {
             withContext(Dispatchers.IO) {
-                GameMetadata.resetMetadata()
+                if (firstStartup) {
+                    // Retrieve list of cached games
+                    val storedGames =
+                        PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
+                            .getStringSet(GameHelper.KEY_GAMES, emptySet())
+                    if (storedGames!!.isNotEmpty()) {
+                        val deserializedGames = mutableSetOf<Game>()
+                        storedGames.forEach {
+                            val game: Game
+                            try {
+                                game = Json.decodeFromString(it)
+                            } catch (e: Exception) {
+                                // We don't care about any errors related to parsing the game cache
+                                return@forEach
+                            }
+
+                            val gameExists =
+                                DocumentFile.fromSingleUri(
+                                    YuzuApplication.appContext,
+                                    Uri.parse(game.path)
+                                )?.exists()
+                            if (gameExists == true) {
+                                deserializedGames.add(game)
+                            }
+                        }
+                        setGames(deserializedGames.toList())
+                    }
+                }
+
                 setGames(GameHelper.getGames())
                 setGames(GameHelper.getGames())
+                reloading.set(false)
                 _isReloading.value = false
                 _isReloading.value = false
 
 
                 if (directoriesChanged) {
                 if (directoriesChanged) {