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: Leverage FlexibleListAdapter more in dialogs (Disable item anims)
* TODO: Add more logging
* TODO: Try to move on from shared objs in synchronized and volatile
*/
@AndroidEntryPoint
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.
* @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) {
/**

View file

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