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

如何在Android ListView中加载从设备存储选取的音频文件?

问题修复方案

现有代码核心问题

  • Intent 重复设置Action,同时配置ACTION_OPEN_DOCUMENT和ACTION_GET_CONTENT会导致行为冲突
  • 拿到返回的Uri后,没有解析音频对应的标题、艺术家、资源路径,也没有将新的歌曲数据添加到listSongs数据源中
  • Adapter 初始化和绑定逻辑写在判断分支外,不管有没有选中音频都会重新创建Adapter,且数据源没有更新自然不会展示新条目
  • 缺少动态权限申请逻辑,Android 6.0及以上系统如果没有读取存储权限,无法获取音频元数据

完整修改步骤

1. 提前声明所需常量和全局变量

private val PICK_AUDIO = 1001
private val REQUEST_STORAGE_PERMISSION = 1002
private lateinit var audioUri: Uri
// 注意SongBean为自定义歌曲实体类,需自行定义包含title、artist、path三个属性
private val listSongs = mutableListOf<SongBean>()
private lateinit var adapter: SongsAdapter

2. 页面初始化时一次性绑定Adapter,不要每次选文件都重复创建

// 该逻辑放在页面onCreate生命周期中执行即可
adapter = SongsAdapter(listSongs)
twoTracksListView.adapter = adapter

3. 修改loadSong方法,先校验权限再跳转文件选择页

private fun loadSong() {
    // 校验存储读取权限
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), REQUEST_STORAGE_PERMISSION)
        return
    }
    val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
        type = "audio/*"
    }
    startActivityForResult(Intent.createChooser(intent, "选择音频"), PICK_AUDIO)
}

4. 修改onActivityResult逻辑,解析音频数据后更新列表

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == PICK_AUDIO && resultCode == RESULT_OK && data != null) {
        audioUri = data.data ?: return
        // 解析Uri对应的音频元数据
        val song = getSongFromUri(audioUri)
        song?.let {
            listSongs.add(it)
            // 通知Adapter数据源更新
            adapter.notifyDataSetChanged()
        }
    }
}

// 新增音频元数据解析方法
private fun getSongFromUri(uri: Uri): SongBean? {
    var song: SongBean? = null
    val projection = arrayOf(
        MediaStore.Audio.Media.TITLE,
        MediaStore.Audio.Media.ARTIST,
        MediaStore.Audio.Media.DATA
    )
    contentResolver.query(uri, projection, null, null, null)?.use { cursor ->
        if (cursor.moveToFirst()) {
            val title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE))
            val artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST))
            val path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA))
            song = SongBean(title, artist, path)
        }
    }
    return song
}

5. 清单文件添加权限声明

<!-- Android 12及以下版本权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Android 13及以上版本权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

内容的提问来源于stack exchange,提问作者TeerLs

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 06:45:03