You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:如何为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()
    }
}

注意事项

  1. 确保Music类中存在type字段(你创建本地歌曲实例时已传入"local",此部分无需额外修改)
  2. 本地歌曲播放需确保已申请对应权限:Android 10及以上可使用媒体库权限,Android 9及以下需申请READ_EXTERNAL_STORAGE权限

内容的提问来源于stack exchange,提问作者Ngọc Hưng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 19:59:56