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:
parent
7ea7c72dde
commit
f9d4827102
|
@ -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) {
|
||||||
|
|
Reference in New Issue