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

Environment.getExternalStorageDirectory()废弃后MP3播放器扫描音频方案咨询

MP3播放器音频文件读取修复方案

以下提供两种可直接落地的方案,适配所有安卓版本,你可以根据需求选择:


方案1:应用私有存储方案(无需额外权限,满足你说的内部存储需求)

该方案读取的是APP专属的存储目录,不需要申请任何存储权限,卸载APP时文件会同步删除,适合不需要读取系统公共音频的场景。

修改步骤:

  1. 可直接删除原有Dexter权限申请逻辑(私有目录访问不需要权限)
  2. 将原有代码中获取根目录的代码:
ArrayList<File> mySongs = fetchSongs(Environment.getExternalStorageDirectory());

替换为:

// 用外部私有存储的音乐目录,也可以换成getFilesDir()用纯内部存储
ArrayList<File> mySongs = fetchSongs(getExternalFilesDir(Environment.DIRECTORY_MUSIC));
  1. 测试时将你的MP3文件放入设备的 Android/data/com.example.musicplayer/files/Music 目录下即可被扫描到。

方案2:扫描系统所有公共MP3文件(兼容全安卓版本)

如果需要读取用户设备里所有存储的音频文件,用官方推荐的MediaStore媒体库方案,比手动遍历文件夹效率高10倍以上,且兼容安卓4.4到最新版本。

修改步骤:

  1. 先修改AndroidManifest.xml配置:
    在<application>节点添加属性:
android:requestLegacyExternalStorage="true"

在<manifest>节点下添加权限配置:

<!-- 安卓12及以下权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<!-- 安卓13及以上权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
  1. 替换MainActivity的逻辑:
    将原有权限申请+扫描逻辑替换为以下代码,原有的fetchSongs方法可以直接删除:
package com.example.musicplayer;

import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.database.Cursor;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionDeniedResponse;
import com.karumi.dexter.listener.PermissionGrantedResponse;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.single.PermissionListener;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    ListView listview;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listview = findViewById(R.id.listview);
        
        // 动态判断安卓版本申请对应权限
        String permission = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU ? 
                Manifest.permission.READ_MEDIA_AUDIO : Manifest.permission.READ_EXTERNAL_STORAGE;
        
        Dexter.withContext(this)
                .withPermission(permission)
                .withListener(new PermissionListener() {
                    @Override
                    public void onPermissionGranted(PermissionGrantedResponse permissionGrantedResponse) {
                        Toast.makeText(MainActivity.this, "权限获取成功", Toast.LENGTH_SHORT).show();
                        ArrayList<String> songNames = fetchAllMp3FromMediaStore();
                        ArrayAdapter<String> adapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_list_item_1, songNames);
                        listview.setAdapter(adapter);
                    }

                    @Override
                    public void onPermissionDenied(PermissionDeniedResponse permissionDeniedResponse) {
                        Toast.makeText(MainActivity.this, "请授予存储权限才能扫描音频", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onPermissionRationaleShouldBeShown(PermissionRequest permissionRequest, PermissionToken permissionToken) {
                        permissionToken.continuePermissionRequest();
                    }
                })
                .check();
    }
    
    // 从系统媒体库查询所有MP3文件
    private ArrayList<String> fetchAllMp3FromMediaStore() {
        ArrayList<String> songList = new ArrayList<>();
        String[] projection = {MediaStore.Audio.Media.DISPLAY_NAME};
        String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0 AND " + MediaStore.Audio.Media.DISPLAY_NAME + " LIKE '%.mp3'";
        
        Cursor cursor = getContentResolver().query(
                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                projection,
                selection,
                null,
                MediaStore.Audio.Media.DISPLAY_NAME + " ASC"
        );
        
        if (cursor != null) {
            while (cursor.moveToNext()) {
                String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME));
                // 去掉.mp3后缀
                songList.add(name.replace(".mp3", ""));
            }
            cursor.close();
        }
        return songList;
    }
}

注意事项

  • 安卓13以上首次启动会弹出音频权限申请弹窗,用户授权后才能扫描所有音频
  • 如果需要获取音频的完整路径、时长等信息,只需要在projection数组里添加对应的MediaStore字段即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 02:06:04