android: Fix games list loading thread safety

Previously we relied on a stateflow for reloading state. Now we use an atomic boolean.
This commit is contained in:
t895 2023-12-10 20:54:00 -05:00
parent 7ea7c72dde
commit f9d4827102

View File

@ -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 getGameDirs()
val storedGames = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) reloadGames(directoriesChanged = false, firstStartup = true)
.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)
}
}
} }
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) { fun reloadGames(directoriesChanged: Boolean, firstStartup: Boolean = false) {
if (isReloading.value) { 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) {