playback: fix crash on state restore

Fix a crash stemming from applying the playback state on the main
thread instead of the background thread.

all: add misc todos
This commit is contained in:
Alexander Capehart 2023-06-03 09:04:44 -06:00
parent 182883ef2d
commit 736f3ec6b7
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
5 changed files with 10 additions and 7 deletions

View file

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

View file

@ -22,6 +22,7 @@ import android.view.View
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logW
/**
* A [RecyclerView.Adapter] that supports indicating the playback status of a particular item.
@ -71,7 +72,7 @@ abstract class PlayingIndicatorAdapter<T, VH : RecyclerView.ViewHolder>(
if (pos > -1) {
notifyItemChanged(pos, PAYLOAD_PLAYING_INDICATOR_CHANGED)
} else {
logD("oldItem was not in adapter data")
logW("oldItem was not in adapter data")
}
}
@ -81,7 +82,7 @@ abstract class PlayingIndicatorAdapter<T, VH : RecyclerView.ViewHolder>(
if (pos > -1) {
notifyItemChanged(pos, PAYLOAD_PLAYING_INDICATOR_CHANGED)
} else {
logD("newItem was not in adapter data")
logW("newItem was not in adapter data")
}
}
@ -99,7 +100,7 @@ abstract class PlayingIndicatorAdapter<T, VH : RecyclerView.ViewHolder>(
if (pos > -1) {
notifyItemChanged(pos, PAYLOAD_PLAYING_INDICATOR_CHANGED)
} else {
logD("newItem was not in adapter data")
logW("newItem was not in adapter data")
}
}
}

View file

@ -161,6 +161,7 @@ private class UserLibraryImpl(
override fun findPlaylist(name: String) = playlistMap.values.find { it.name.raw == name }
override suspend fun createPlaylist(name: String, songs: List<Song>) {
// TODO: Use synchronized with value access too
val playlistImpl = PlaylistImpl.from(name, songs, musicSettings)
synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl }
val rawPlaylist =

View file

@ -236,13 +236,11 @@ class PlaybackPanelFragment :
requireBinding().playbackShuffle.isActivated = isShuffled
}
/** Navigate to one of the currently playing [Song]'s Artists. */
private fun navigateToCurrentArtist() {
val song = playbackModel.song.value ?: return
navModel.exploreNavigateToParentArtist(song)
}
/** Navigate to the currently playing [Song]'s albums. */
private fun navigateToCurrentAlbum() {
val song = playbackModel.song.value ?: return
navModel.exploreNavigateTo(song.album)

View file

@ -44,6 +44,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.MusicSettings
@ -355,7 +356,9 @@ class PlaybackService :
logD("Restoring playback state")
restoreScope.launch {
persistenceRepository.readState()?.let {
playbackManager.applySavedState(it, false)
// Apply the saved state on the main thread to prevent code expecting
// state updates on the main thread from crashing.
withContext(Dispatchers.Main) { playbackManager.applySavedState(it, false) }
}
}
}