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

获取本地存储歌曲流派时应用崩溃,求解决方案

解决Android获取设备歌曲流派时应用崩溃的问题

我知道该问题此前已有提问,但尚未找到解决方案。我尝试获取设备存储中歌曲的流派,但运行以下代码时应用崩溃:

public void getMusic() { 
    ContentResolver contentResolver = getContentResolver(); 
    Uri songUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; 
    Cursor songCursor = contentResolver.query(songUri, null, null, null, null); 
    if (songCursor != null && songCursor.moveToFirst()) { 
        int songTitle = songCursor.getColumnIndex(Media...
    }
}

我来帮你排查下这个崩溃问题,结合Android媒体存储的机制,你的代码大概率是因为权限缺失、空值未处理、Cursor使用不规范这几个原因导致的,下面是具体的修复方案:

一、先明确崩溃的核心原因

  1. 权限未申请或未校验:Android 12及以下需要READ_EXTERNAL_STORAGE权限,Android 13+则需要READ_MEDIA_AUDIO权限,没申请直接访问媒体库会抛出SecurityException导致崩溃。
  2. Cursor列处理不当:你代码里用null作为query的投影参数(即获取所有列),但如果流派字段为空或者索引获取错误,直接取值会触发异常;而且你代码里的Media...没写完,大概率是要获取MediaStore.Audio.Media.GENRE字段,这个字段本身可能为空,必须做空值判断。
  3. Cursor未正确关闭:如果Cursor使用后不关闭,会导致内存泄漏,极端情况也会引发崩溃。

二、修复后的完整代码

// 定义需要获取的媒体列,避免获取不必要的数据
private static final String[] MUSIC_PROJECTION = {
    MediaStore.Audio.Media._ID,
    MediaStore.Audio.Media.TITLE,
    MediaStore.Audio.Media.ARTIST,
    MediaStore.Audio.Media.GENRE // 目标流派字段
};

public void getMusic() {
    // 先校验权限,不同Android版本权限不同
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_AUDIO)
                != PackageManager.PERMISSION_GRANTED) {
            // 申请Android13+的音频权限
            registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
                if (isGranted) loadMusicData();
                else Toast.makeText(this, "需要音频权限才能获取歌曲信息", Toast.LENGTH_SHORT).show();
            }).launch(Manifest.permission.READ_MEDIA_AUDIO);
            return;
        }
    } else {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            // 申请旧版本的存储权限
            registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
                if (isGranted) loadMusicData();
                else Toast.makeText(this, "需要存储权限才能获取歌曲信息", Toast.LENGTH_SHORT).show();
            }).launch(Manifest.permission.READ_EXTERNAL_STORAGE);
            return;
        }
    }

    // 权限已通过,加载音乐数据
    loadMusicData();
}

private void loadMusicData() {
    ContentResolver contentResolver = getContentResolver();
    Uri songUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;

    // 使用指定投影查询,减少资源占用
    Cursor songCursor = contentResolver.query(songUri, MUSIC_PROJECTION, null, null, null);

    if (songCursor != null) {
        try {
            // 获取列索引,避免硬编码位置
            int genreColIndex = songCursor.getColumnIndex(MediaStore.Audio.Media.GENRE);
            int titleColIndex = songCursor.getColumnIndex(MediaStore.Audio.Media.TITLE);

            while (songCursor.moveToNext()) {
                // 处理流派字段为空的情况
                String genre = songCursor.isNull(genreColIndex) ? "未知流派" : songCursor.getString(genreColIndex);
                String songTitle = songCursor.getString(titleColIndex);

                // 这里可以把数据加入列表或做其他处理
                Log.d("MusicInfo", "歌曲:" + songTitle + " | 流派:" + genre);
            }
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(this, "获取歌曲信息失败", Toast.LENGTH_SHORT).show();
        } finally {
            // 务必关闭Cursor,释放系统资源
            songCursor.close();
        }
    }
}

三、额外注意事项

  • 流派字段的局限性:部分音乐文件可能没有嵌入流派元数据,或者MediaStore未正确索引,此时GENRE字段会为空,一定要用isNull()做判断。
  • 更精准的流派获取:如果MediaStore的流派信息不全,你可以直接解析音乐文件的元数据:
    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
    retriever.setDataSource("你的音乐文件路径");
    String genre = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE);
    retriever.release(); // 记得释放资源
    
  • 权限申请的时机:最好在用户触发获取音乐的操作时再申请权限,避免启动时就弹出权限弹窗影响体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:24:51