我正在尝试使用 Jetpack Compose 编写音乐播放器应用程序。我有一个如下所示的 MusicCardModel
data class MusicCardModel(
val contentUri: Uri?,
val songId: Long?,
val cover: Bitmap?,
val songTitle: String?,
val artist: String?,
val duration: String?
)
当我启动应用程序时,我正在使用以下功能的 MediaStore 扫描所有音乐文件
@SuppressLint("Recycle")
fun Context.musicList(): MutableList<MusicCardModel> {
val list = mutableListOf<MusicCardModel>()
val collection =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
} else {
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
val projection = arrayOf(
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media.ARTIST
)
val selection = MediaStore.Audio.Media.IS_MUSIC + "!= 0"
val sortOrder = "${MediaStore.Audio.Media.DISPLAY_NAME} ASC"
val query = this.contentResolver.query(
collection,
projection,
selection,
null,
sortOrder
)
query?.use { cursor ->
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)
val durationColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION)
val titleColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)
val artistColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST)
val albumIdColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID)
while (cursor.moveToNext()) {
val id = cursor.getLong(idColumn)
val duration = cursor.getInt(durationColumn)
val title = cursor.getString(titleColumn)
val artist = cursor.getString(artistColumn)
val albumId = cursor.getLong(albumIdColumn)
val contentUri: Uri = ContentUris.withAppendedId(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
id
)
val bitmap = getAlbumArt(this, contentUri)
val durationString = convertMili(duration)
list.add(MusicCardModel(contentUri, id, bitmap, title, artist, durationString))
}
}
return list
}
fun getAlbumArt(context: Context, uri: Uri): Bitmap{
val mmr = MediaMetadataRetriever()
mmr.setDataSource(context, uri)
val data = mmr.embeddedPicture
return if(data != null){
BitmapFactory.decodeByteArray(data, 0, data.size)
}else{
BitmapFactory.decodeResource(context.resources, R.drawable.note)
}
}
显示该列表的这些代码部分
Box(modifier = Modifier
.padding(bottom = if (isPlaying.value) 80.dp else 0.dp)){
LazyColumn {
items(list) { index ->
MusicCard(
uri = index.contentUri!!,
songId = index.songId,
artist = index.artist!!,
name = index.songTitle!!,
duration = index.duration!!,
isPlaying = isPlaying,
playingSong = playingSong
)
}
}
}
@Composable
fun MusicCard(
uri: Uri,
artist: String,
name: String,
cover: Bitmap?,
duration: String,
isPlaying: MutableState<Boolean>,
playingSong: MutableState<MusicCardModel>,
songId: Long?,
playState: MutableState<Boolean>
) {
val context = LocalContext.current
Card(modifier = Modifier
.fillMaxWidth()
.clickable {
playMusic(context, uri)
playState.value = true
isPlaying.value = true
val playingSongModel = MusicCardModel(uri, songId,
null, name, artist, duration)
playingSong.value = playingSongModel
}
) {
Row(
modifier = Modifier.padding(10.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Row(
modifier = Modifier.weight(1f),
verticalAlignment = Alignment.CenterVertically
) {
Image(
modifier = Modifier.size(70.dp),
bitmap = cover!!.asImageBitmap(),
contentDescription = "Cover Photo",
)
Column(
modifier = Modifier
.padding(horizontal = 10.dp)
) {
Text(
modifier = Modifier.padding(vertical = 5.dp),
text = artist
)
Text (name, maxLines = 1)
}
}
Text(text = duration)
}
}
}
有2个问题。第一个是创建这个列表,专辑艺术花费了太多时间,并且等待很长时间才能在屏幕上显示该列表。没有专辑封面它非常快,但我想展示专辑封面。如何延迟加载音乐文件的元数据?第二个问题是将所有这些列表数据加载到内存中,当我切换到另一个应用程序并且应用程序停止时,会出现 TransactionTooLargeException。我该如何解决这些问题?