Android新手求助:将raw/asset文件夹MP3文件加载至RecyclerView
从raw/Assets文件夹读取MP3文件的Android实现方案
我是Android开发入门新手,之前做了一个读取设备本地音乐的应用,现在想改成读取raw或asset文件夹里的MP3文件,看了很多视频还是没解决,附上我的现有代码,求帮忙。
现有MainActivity代码
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RecyclerView recyclerView = findViewById(R.id.recyclerview); if (checkPermission() == false){ requesPermission(); return; } String[] projection = { MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DURATION }; String selection = MediaStore.Audio.Media.IS_MUSIC +" != 0"; Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,projection,selection,null,null); while (cursor.moveToNext()){ AudioModel songdata = new AudioModel(cursor.getString(1),cursor.getString(0),cursor.getString(2)); if (new File(songdata.getPath()).exists()) songlist.add(songdata); } recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(new MusicListAdapter(songlist,getApplicationContext())); }
现有MusicListAdapter代码
public class MusicListAdapter extends RecyclerView.Adapter<MusicListAdapter.MyViewHolder> { ArrayList<AudioModel> songlist; Context context; public MusicListAdapter(ArrayList<AudioModel> songlist, Context context) { this.songlist = songlist; this.context = context; } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(context).inflate(R.layout.item_view,parent,false); return new MusicListAdapter.MyViewHolder(view); } @Override public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { AudioModel songData = songlist.get(position); holder.track_name.setText(songData.getTitle()); if (MyMediaPlayer.currentIndex==position){ holder.track_name.setTextColor(Color.parseColor("#FF0000")); }else { holder.track_name.setTextColor(Color.parseColor("#000000")); } holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { MyMediaPlayer.getInstance().reset(); MyMediaPlayer.currentIndex = position; Intent intent = new Intent(context,MusicPlayerActivity.class); intent.putExtra("LIST",songlist); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } }); } @Override public int getItemCount() { return songlist.size(); } public class MyViewHolder extends RecyclerView.ViewHolder { ImageView track_icon; TextView track_name,track_artist; public MyViewHolder(@NonNull View itemView) { super(itemView); track_icon = itemView.findViewById(R.id.track_icon); track_name = itemView.findViewById(R.id.track_name); track_artist = itemView.findViewById(R.id.track_artist); } } }
现有AudioModel代码
public class AudioModel implements Serializable { String path; String title; String duration; String icon; public AudioModel(String path, String title, String duration) { this.path = path; this.title = title; //this.duration = duration; } public String getPath() { return path; } public String getTitle() { return title; } public String getDuration() { return duration; } public void setPath(String path) { this.path = path; } public void setTitle(String title) { this.title = title; } public void setDuration(String duration) { this.duration = duration; } }
解决方案
一、读取res/raw文件夹中的MP3文件
- 前置操作:将MP3文件放入
res/raw文件夹,文件名只能用小写字母、数字和下划线,不能有空格或特殊字符。 - 修改MainActivity逻辑:替换原来的MediaStore查询代码,直接读取raw资源,无需权限申请。
修改后的MainActivity核心代码:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RecyclerView recyclerView = findViewById(R.id.recyclerview); songlist = new ArrayList<>(); // 确保songlist已初始化 // 读取raw文件夹中的音频文件 Field[] fields = R.raw.class.getFields(); for (Field field : fields) { try { int resId = field.getInt(null); String title = field.getName(); // 用文件名作为音频标题 // 构建raw资源的Uri路径 String path = "android.resource://" + getPackageName() + "/raw/" + title; // 获取音频时长(可选,需提前解析) MediaPlayer mp = MediaPlayer.create(this, resId); String duration = String.valueOf(mp.getDuration()); mp.release(); AudioModel songdata = new AudioModel(path, title, duration); songlist.add(songdata); } catch (Exception e) { e.printStackTrace(); } } recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(new MusicListAdapter(songlist, getApplicationContext())); }
二、读取Assets文件夹中的MP3文件
- 前置操作:将MP3文件放入
assets文件夹,可创建子文件夹(如assets/music),文件名无严格限制。 - 修改MainActivity逻辑:通过AssetManager获取文件列表。
修改后的MainActivity核心代码:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RecyclerView recyclerView = findViewById(R.id.recyclerview); songlist = new ArrayList<>(); // 读取assets文件夹中的音频文件(若放在子文件夹music下,list参数传"music",否则传"") AssetManager assetManager = getAssets(); try { String[] files = assetManager.list("music"); for (String fileName : files) { if (fileName.endsWith(".mp3")) { String title = fileName.substring(0, fileName.lastIndexOf(".")); // 自定义路径标识,用于播放时区分 String path = "asset:///" + fileName; // 获取音频时长(可选) AssetFileDescriptor afd = assetManager.openFd("music/" + fileName); MediaPlayer mp = new MediaPlayer(); mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); mp.prepare(); String duration = String.valueOf(mp.getDuration()); mp.release(); afd.close(); AudioModel songdata = new AudioModel(path, title, duration); songlist.add(songdata); } } } catch (IOException e) { e.printStackTrace(); } recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(new MusicListAdapter(songlist, getApplicationContext())); }
三、播放逻辑适配(修改MyMediaPlayer)
raw和assets资源的播放方式与本地文件不同,需修改播放逻辑:
public class MyMediaPlayer { private static MediaPlayer instance; public static int currentIndex = -1; public static MediaPlayer getInstance() { if (instance == null) { instance = new MediaPlayer(); } return instance; } public void play(String path, Context context) { try { reset(); if (path.startsWith("android.resource://")) { // 播放raw资源 setDataSource(context, Uri.parse(path)); } else if (path.startsWith("asset:///")) { // 播放assets资源 String fileName = path.replace("asset:///", ""); // 若放在子文件夹,需拼接路径,比如"music/" + fileName AssetFileDescriptor afd = context.getAssets().openFd(fileName); setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); afd.close(); } else { // 兼容原有本地文件播放逻辑 setDataSource(path); } prepare(); start(); } catch (IOException e) { e.printStackTrace(); } } }
四、注意事项
- 获取音频时长的操作建议放在子线程执行,避免阻塞主线程
- 使用完MediaPlayer和AssetFileDescriptor后,务必调用
release()和close()释放资源 - raw资源会被编译进APK,无法动态修改;assets资源可保留原始文件结构,支持动态读取
内容的提问来源于stack exchange,提问作者Bra Him
相关产品推荐
相关产品推荐

