music: try to fix repo race conditions

Forgot to slather the entire class in Synchronized and Volatile. Should
make crashes less likely, I hope.
This commit is contained in:
Alexander Capehart 2023-05-21 09:53:07 -06:00
parent 049d2bc152
commit 8953f12a1e
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
3 changed files with 27 additions and 28 deletions

View file

@ -51,6 +51,7 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat
* TODO: Fix UID naming * TODO: Fix UID naming
* TODO: Leverage FlexibleListAdapter more in dialogs (Disable item anims) * TODO: Leverage FlexibleListAdapter more in dialogs (Disable item anims)
* TODO: Add more logging * TODO: Add more logging
* TODO: Try to move on from shared objs in synchronized and volatile
*/ */
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {

View file

@ -26,6 +26,8 @@ import org.oxycblt.auxio.util.logE
* *
* @param mode The type of list in the home view this instance corresponds to. * @param mode The type of list in the home view this instance corresponds to.
* @author Alexander Capehart (OxygenCobalt) * @author Alexander Capehart (OxygenCobalt)
*
* TODO: Tab migration to playlists is busted and resets the config entirely. Need to fix.
*/ */
sealed class Tab(open val mode: MusicMode) { sealed class Tab(open val mode: MusicMode) {
/** /**

View file

@ -219,12 +219,12 @@ constructor(
) : MusicRepository { ) : MusicRepository {
private val updateListeners = mutableListOf<MusicRepository.UpdateListener>() private val updateListeners = mutableListOf<MusicRepository.UpdateListener>()
private val indexingListeners = mutableListOf<MusicRepository.IndexingListener>() private val indexingListeners = mutableListOf<MusicRepository.IndexingListener>()
private var indexingWorker: MusicRepository.IndexingWorker? = null @Volatile private var indexingWorker: MusicRepository.IndexingWorker? = null
override var deviceLibrary: DeviceLibrary? = null @Volatile override var deviceLibrary: DeviceLibrary? = null
override var userLibrary: MutableUserLibrary? = null @Volatile override var userLibrary: MutableUserLibrary? = null
private var previousCompletedState: IndexingState.Completed? = null @Volatile private var previousCompletedState: IndexingState.Completed? = null
private var currentIndexingState: IndexingState? = null @Volatile private var currentIndexingState: IndexingState? = null
override val indexingState: IndexingState? override val indexingState: IndexingState?
get() = currentIndexingState ?: previousCompletedState get() = currentIndexingState ?: previousCompletedState
@ -272,55 +272,50 @@ constructor(
currentIndexingState = null currentIndexingState = null
} }
@Synchronized
override fun find(uid: Music.UID) = override fun find(uid: Music.UID) =
(deviceLibrary?.run { findSong(uid) ?: findAlbum(uid) ?: findArtist(uid) ?: findGenre(uid) } (deviceLibrary?.run { findSong(uid) ?: findAlbum(uid) ?: findArtist(uid) ?: findGenre(uid) }
?: userLibrary?.findPlaylist(uid)) ?: userLibrary?.findPlaylist(uid))
override suspend fun createPlaylist(name: String, songs: List<Song>) { override suspend fun createPlaylist(name: String, songs: List<Song>) {
val userLibrary = userLibrary ?: return val userLibrary = synchronized(this) { userLibrary ?: return }
userLibrary.createPlaylist(name, songs) userLibrary.createPlaylist(name, songs)
for (listener in updateListeners) { notifyUserLibraryChange()
listener.onMusicChanges(
MusicRepository.Changes(deviceLibrary = false, userLibrary = true))
}
} }
override suspend fun renamePlaylist(playlist: Playlist, name: String) { override suspend fun renamePlaylist(playlist: Playlist, name: String) {
val userLibrary = userLibrary ?: return val userLibrary = synchronized(this) { userLibrary ?: return }
userLibrary.renamePlaylist(playlist, name) userLibrary.renamePlaylist(playlist, name)
for (listener in updateListeners) { notifyUserLibraryChange()
listener.onMusicChanges(
MusicRepository.Changes(deviceLibrary = false, userLibrary = true))
}
} }
override suspend fun deletePlaylist(playlist: Playlist) { override suspend fun deletePlaylist(playlist: Playlist) {
val userLibrary = userLibrary ?: return val userLibrary = synchronized(this) { userLibrary ?: return }
userLibrary.deletePlaylist(playlist) userLibrary.deletePlaylist(playlist)
for (listener in updateListeners) { notifyUserLibraryChange()
listener.onMusicChanges(
MusicRepository.Changes(deviceLibrary = false, userLibrary = true))
}
} }
override suspend fun addToPlaylist(songs: List<Song>, playlist: Playlist) { override suspend fun addToPlaylist(songs: List<Song>, playlist: Playlist) {
val userLibrary = userLibrary ?: return val userLibrary = synchronized(this) { userLibrary ?: return }
userLibrary.addToPlaylist(playlist, songs) userLibrary.addToPlaylist(playlist, songs)
for (listener in updateListeners) { notifyUserLibraryChange()
listener.onMusicChanges(
MusicRepository.Changes(deviceLibrary = false, userLibrary = true))
}
} }
override suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>) { override suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>) {
val userLibrary = userLibrary ?: return val userLibrary = synchronized(this) { userLibrary ?: return }
userLibrary.rewritePlaylist(playlist, songs) userLibrary.rewritePlaylist(playlist, songs)
notifyUserLibraryChange()
}
@Synchronized
private fun notifyUserLibraryChange() {
for (listener in updateListeners) { for (listener in updateListeners) {
listener.onMusicChanges( listener.onMusicChanges(
MusicRepository.Changes(deviceLibrary = false, userLibrary = true)) MusicRepository.Changes(deviceLibrary = false, userLibrary = true))
} }
} }
@Synchronized
override fun requestIndex(withCache: Boolean) { override fun requestIndex(withCache: Boolean) {
indexingWorker?.requestIndex(withCache) indexingWorker?.requestIndex(withCache)
} }
@ -400,9 +395,10 @@ constructor(
throw NoMusicException() throw NoMusicException()
} }
// Successfully loaded the library, now save the cache and create the library in // Successfully loaded the library, now save the cache, create the library, and
// parallel. // read playlist information in parallel.
logD("Discovered ${rawSongs.size} songs, starting finalization") logD("Discovered ${rawSongs.size} songs, starting finalization")
// TODO: Indicate playlist state in loading process?
emitLoading(IndexingProgress.Indeterminate) emitLoading(IndexingProgress.Indeterminate)
val deviceLibraryChannel = Channel<DeviceLibrary>() val deviceLibraryChannel = Channel<DeviceLibrary>()
val deviceLibraryJob = val deviceLibraryJob =