求助:如何为MediaPlayer设置本地歌曲数据源以实现播放
本地歌曲播放数据源适配解决方案
问题描述
我正在开发一款支持在线与本地歌曲播放的个人项目,已完成在线歌曲播放功能,但在本地歌曲播放环节遇到问题:已成功获取所有本地歌曲的列表,却无法播放这些歌曲。原因是MusicService中的startMusic方法仅适配在线歌曲场景,不知道该如何为本地歌曲设置数据源。
原有代码
MusicService中的startMusic函数
fun startMusic(song: Music) { isServiceStart = true music = song position = music.position - 1 mediaPlayer.reset() mediaPlayer.setDataSource("https://api.mp3.zing.vn/api/streaming/audio/${song.id}/320") mediaPlayer.prepare() mediaPlayer.start() sendActionToActivity(AppConstants.ACTION_START) sendMusicToActivity(music) sendNotificationMedia(song, true) mediaPlayer.setOnCompletionListener { playNextSong() } }
获取本地歌曲列表的实现
private fun getMusic(): MutableList<Music> { val musicList = mutableListOf<Music>() val projection = arrayOf( MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DURATION ) val selection = "${MediaStore.Audio.Media.IS_MUSIC} != 0" val sortOrder = "${MediaStore.Audio.Media.TITLE} ASC" requireContext().contentResolver.query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, null, sortOrder )?.use { cursor -> val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID) val titleColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE) val artistColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST) val dataColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA) val durationColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION) var position = 0 while (cursor.moveToNext()) { val id = cursor.getString(idColumn) val title = cursor.getString(titleColumn) val artist = cursor.getString(artistColumn) val data = cursor.getString(dataColumn) val duration = cursor.getInt(durationColumn) / 1000 // Convert to seconds val music = Music(id, title, artist, data, position++, "local", duration, "") musicList.add(music) } } return musicList }
解决方案
核心思路是根据歌曲的类型(你已经在Music实例中标记为"local")来切换数据源:
- 在线歌曲:保持原有的Zing API地址作为数据源
- 本地歌曲:使用从
MediaStore获取到的data字段(本地文件路径)作为数据源
修改后的startMusic函数如下:
fun startMusic(song: Music) { isServiceStart = true music = song position = music.position - 1 mediaPlayer.reset() // 根据歌曲类型设置不同数据源 val dataSource = if (song.type == "local") { song.data // 本地歌曲用MediaStore获取到的文件路径 } else { "https://api.mp3.zing.vn/api/streaming/audio/${song.id}/320" // 在线歌曲用原API地址 } try { mediaPlayer.setDataSource(dataSource) mediaPlayer.prepare() mediaPlayer.start() } catch (e: IOException) { e.printStackTrace() // 可添加播放失败的提示逻辑 } sendActionToActivity(AppConstants.ACTION_START) sendMusicToActivity(music) sendNotificationMedia(song, true) mediaPlayer.setOnCompletionListener { playNextSong() } }
注意事项
- 确保
Music类中存在type字段(你创建本地歌曲实例时已传入"local",此部分无需额外修改) - 本地歌曲播放需确保已申请对应权限:Android 10及以上可使用媒体库权限,Android 9及以下需申请
READ_EXTERNAL_STORAGE权限
内容的提问来源于stack exchange,提问作者Ngọc Hưng
相关产品推荐
相关产品推荐

