ARTICLE AD BOX
I have an app getting metadata from a list of songs using TagLib.
It first gets the song id via MediaStore, and send fd to TagLib which dups it and uses it to open a stream to get the metadata and audio properties.
This returns a map of <String, Array<String>> and an IntArray of size 4.
This is called for every id returned by the MediaStore query.
The first 1700 songs take ~700 ms per 100 songs but every 100 after takes 23 seconds, and increases every 100 up to ~60s.
This method is run on Dispatchers IO.
What can I do to reduce this?
This full scan will be on first app start up so it's not really that concerning.
However 7900+ songs take around 18 minutes for a full scan.
MediaStore scan
fun getAudioFilesViaMediaStore(): List<Song> { //.nomedia affected val musicUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI val projection = arrayOf(MediaStore.Audio.Media._ID) val audioList = mutableListOf<Song>() //TODO replace placeholder path val audioCursor = contentResolver.query( musicUri, projection, "${MediaStore.Audio.Media.RELATIVE_PATH} LIKE ?", arrayOf("%Music%"), null ) ?: return emptyList() audioCursor.use { cursor -> val idColumn: Int = audioCursor.getColumnIndex(MediaStore.Audio.AudioColumns._ID) cursor.apply { if (count == 0) Log.d("Cursor", "get cursor data: Cursor is empty.") else { while (cursor.moveToNext()) { try { val iD = cursor.getLong(idColumn) val song = getSongDetailsTagLib(iD) if (song != null) audioList += song } catch (e: Exception) { Log.e("Cursor read", "ERR", e) } } } } } return audioList }GetSongDetails
fun getSongDetailsTagLib(id: Long): Song? { val uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id) val pfd = contentResolver.openFileDescriptor(uri, "r") ?: return null val fd = pfd.detachFd() val prop: IntArray = TagLib.getAudioProperties(fd) val metadata: HashMap<String, Array<String>> = TagLib.getMetadata(fd) val title = metadata["TITLE"]?.firstOrNull()?.takeIf { it.isNotBlank() } ?: "" val artist = metadata["ARTIST"]?.firstOrNull()?.takeIf { it.isNotBlank() } ?: "" val album = metadata["ALBUM"]?.firstOrNull()?.takeIf { it.isNotBlank() } ?: "" //etcetc pfd.close() return Song( title = title, artist = artist, iD = id ) }Main Activity
lifecycleScope.launch(Dispatchers.IO) { val audioList = getAudioFilesViaMediaStore() }