如何在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
相关产品推荐
相关产品推荐

