music: cache ids in map

Make a map of ids to particular music items, which makes searching for
music items much faster at the cost of higher memory usage.
This commit is contained in:
Alexander Capehart 2022-08-28 19:21:30 -06:00
parent b2085e440e
commit 8a15868ba1
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
3 changed files with 37 additions and 32 deletions

View file

@ -114,7 +114,7 @@ class DetailViewModel(application: Application) :
fun setSongId(id: Long) {
if (_currentSong.value?.run { song.id } == id) return
val library = unlikelyToBeNull(musicStore.library)
val song = requireNotNull(library.songs.find { it.id == id }) { "Invalid song id provided" }
val song = requireNotNull(library.findSongById(id)) { "Invalid song id provided" }
generateDetailSong(song)
}
@ -126,8 +126,7 @@ class DetailViewModel(application: Application) :
fun setAlbumId(id: Long) {
if (_currentAlbum.value?.id == id) return
val library = unlikelyToBeNull(musicStore.library)
val album =
requireNotNull(library.albums.find { it.id == id }) { "Invalid album id provided " }
val album = requireNotNull(library.findAlbumById(id)) { "Invalid album id provided " }
_currentAlbum.value = album
refreshAlbumData(album)
@ -136,8 +135,7 @@ class DetailViewModel(application: Application) :
fun setArtistId(id: Long) {
if (_currentArtist.value?.id == id) return
val library = unlikelyToBeNull(musicStore.library)
val artist =
requireNotNull(library.artists.find { it.id == id }) { "Invalid artist id provided" }
val artist = requireNotNull(library.findArtistById(id)) { "Invalid artist id provided" }
_currentArtist.value = artist
refreshArtistData(artist)
}
@ -145,8 +143,7 @@ class DetailViewModel(application: Application) :
fun setGenreId(id: Long) {
if (_currentGenre.value?.id == id) return
val library = unlikelyToBeNull(musicStore.library)
val genre =
requireNotNull(library.genres.find { it.id == id }) { "Invalid genre id provided" }
val genre = requireNotNull(library.findGenreById(id)) { "Invalid genre id provided" }
_currentGenre.value = genre
refreshGenreData(genre)
}

View file

@ -75,12 +75,37 @@ class MusicStore private constructor() {
val albums: List<Album>,
val songs: List<Song>
) {
/** Find a song in a faster manner by using the album ID as well.. */
fun findSongFast(songId: Long, albumId: Long) =
albums.find { it.id == albumId }.run { songs.find { it.id == songId } }
private val genreIdMap = HashMap<Long, Genre>().apply { genres.forEach { put(it.id, it) } }
private val artistIdMap =
HashMap<Long, Artist>().apply { artists.forEach { put(it.id, it) } }
private val albumIdMap = HashMap<Long, Album>().apply { albums.forEach { put(it.id, it) } }
private val songIdMap = HashMap<Long, Song>().apply { songs.forEach { put(it.id, it) } }
/** Find a [Song] by it's ID. Null if no song exists with that ID. */
fun findSongById(songId: Long) = songIdMap[songId]
/** Find a [Album] by it's ID. Null if no album exists with that ID. */
fun findAlbumById(albumId: Long) = albumIdMap[albumId]
/** Find a [Artist] by it's ID. Null if no artist exists with that ID. */
fun findArtistById(artistId: Long) = artistIdMap[artistId]
/** Find a [Genre] by it's ID. Null if no genre exists with that ID. */
fun findGenreById(genreId: Long) = genreIdMap[genreId]
/** Sanitize an old item to find the corresponding item in a new library. */
fun sanitize(song: Song) = findSongById(song.id)
/** Sanitize an old item to find the corresponding item in a new library. */
fun sanitize(songs: List<Song>) = songs.mapNotNull { sanitize(it) }
/** Sanitize an old item to find the corresponding item in a new library. */
fun sanitize(album: Album) = findAlbumById(album.id)
/** Sanitize an old item to find the corresponding item in a new library. */
fun sanitize(artist: Artist) = findArtistById(artist.id)
/** Sanitize an old item to find the corresponding item in a new library. */
fun sanitize(genre: Genre) = findGenreById(genre.id)
/**
* Find a song for a [uri], this is similar to [findSongFast], but with some kind of content
* Find a song for a [uri], this is similar to [findSong], but with some kind of content
* uri.
* @return The corresponding [Song] for this [uri], null if there isn't one.
*/
@ -94,17 +119,6 @@ class MusicStore private constructor() {
songs.find { it.path.name == displayName }
}
/** Sanitize an old item to find the corresponding item in a new library. */
fun sanitize(song: Song) = songs.find { it.id == song.id }
/** Sanitize an old item to find the corresponding item in a new library. */
fun sanitize(songs: List<Song>) = songs.mapNotNull { sanitize(it) }
/** Sanitize an old item to find the corresponding item in a new library. */
fun sanitize(album: Album) = albums.find { it.id == album.id }
/** Sanitize an old item to find the corresponding item in a new library. */
fun sanitize(artist: Artist) = artists.find { it.id == artist.id }
/** Sanitize an old item to find the corresponding item in a new library. */
fun sanitize(genre: Genre) = genres.find { it.id == genre.id }
}
/** A callback for awaiting the loading of music. */

View file

@ -116,9 +116,9 @@ class PlaybackStateDatabase private constructor(context: Context) :
val parent =
when (rawState.playbackMode) {
PlaybackMode.ALL_SONGS -> null
PlaybackMode.IN_ALBUM -> library.albums.find { it.id == rawState.parentId }
PlaybackMode.IN_ARTIST -> library.artists.find { it.id == rawState.parentId }
PlaybackMode.IN_GENRE -> library.genres.find { it.id == rawState.parentId }
PlaybackMode.IN_ALBUM -> rawState.parentId?.let(library::findAlbumById)
PlaybackMode.IN_ARTIST -> rawState.parentId?.let(library::findArtistById)
PlaybackMode.IN_GENRE -> rawState.parentId?.let(library::findGenreById)
}
return SavedState(
@ -168,15 +168,9 @@ class PlaybackStateDatabase private constructor(context: Context) :
readableDatabase.queryAll(TABLE_NAME_QUEUE) { cursor ->
if (cursor.count == 0) return@queryAll
val songIndex = cursor.getColumnIndexOrThrow(QueueColumns.SONG_ID)
val albumIndex = cursor.getColumnIndexOrThrow(QueueColumns.ALBUM_ID)
while (cursor.moveToNext()) {
library.findSongFast(cursor.getLong(songIndex), cursor.getLong(albumIndex))?.let {
song ->
queue.add(song)
}
library.findSongById(cursor.getLong(songIndex))?.let(queue::add)
}
}