自己写音乐播放器,第一步是拿到本地 MP3。可以递归扫 SD 卡,也可以查系统媒体库 MediaStore——后者自带歌名、专辑、歌手和时长。
一、遍历文件过滤 MP3
本地音乐在手机存储里。一种做法是遍历文件,按后缀过滤:
/**
* 扫描 Sdcard(外部存储)下所有文件
*/
public void scanFileList(File parentFile) {
File[] listFile = parentFile.listFiles();
if (listFile != null) {
for (int i = 0; i < listFile.length; i++) {
File file = listFile[i];
if (file.isDirectory()) {
scanFileList(file);
} else {
if (file.getName().endsWith("mp3")) {
MusicBean music = new MusicBean();
String fileName = file.getName();
music.setMusicName(fileName.substring(0, fileName.length() - ".mp3".length()));
music.setMusicPath(file.getAbsolutePath());
mMusicList.add(music);
}
}
}
}
}
调用后把 MP3 加进 mMusicList。扫盘是耗时操作,必须放进线程;刷新 ListView 再丢回主线程:
new Thread(new Runnable() {
@Override
public void run() {
scanFileList(Environment.getExternalStorageDirectory());
mHandler.post(new Runnable() {
@Override
public void run() {
mAdapter.setListData(mMusicList);
}
});
}
}).start();
MP3 里不止音频数据,还有歌名、专辑、歌手、路径、时长。靠递归读这些字段,得按文件格式自己解析。
二、查 MediaStore 媒体库
Android 启动、拔插 SD 卡时会发扫描广播,扫描服务把结果写入媒体库。URI 是 MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,直接 query 就能拿。
查指定目录:
Cursor cursor = getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,
MediaStore.Audio.Media.DATA + " like ?",
new String[]{dirName + "%"},
MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
查全部:
Cursor cursor = getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null,
MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
结果里不只有 MP3,要再过滤。常用字段:
-
歌曲 ID:
MediaStore.Audio.Media._ID
-
-
-
-
-
-
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
String isMusic = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.IS_MUSIC));
if (isMusic != null && isMusic.equals("")) continue;
String title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
if (isRepeat(title, artist)) continue;
music = new Music();
music.setId(cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)));
music.setTitle(title);
music.setArtist(artist);
music.setUri(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)));
music.setLength(cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION)));
music.setImage(getAlbumImage(cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID))));
Constances.mMediaLists.add(music);
}
isRepeat() 按歌名+歌手去重;getAlbumImage() 按 album_id 读封面路径:
private boolean isRepeat(String title, String artist) {
for (Music music : Constances.mMediaLists) {
if (title.equals(music.getTitle()) && artist.equals(music.getArtist())) {
return true;
}
}
return false;
}
private String getAlbumImage(int albumId) {
String result = "";
Cursor cursor = null;
try {
cursor = getContentResolver().query(
Uri.parse("content://media/external/audio/albums/" + albumId),
new String[]{"album_art"}, null, null, null);
for (cursor.moveToFirst(); !cursor.isAfterLast(); ) {
result = cursor.getString(0);
break;
}
} catch (Exception e) {
} finally {
if (null != cursor) {
cursor.close();
}
}
return null == result ? null : result;
}
三、列表展示
Music music = (Music) getItem(position);
Bitmap icon = BitmapFactory.decodeFile(music.getImage());
holder.icon.setImageBitmap(icon == null
? BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)
: icon);
holder.title.setText(music.getTitle());
holder.artist.setText(music.getArtist());

| 方式 |
拿到什么 |
注意 |
| 扫文件 |
路径 + 文件名 |
必须进线程;ID3 要自己解析 |
| MediaStore |
标题、歌手、时长、封面 |
过滤非音乐、去重、关掉 Cursor |
一句话总结:只要文件路径可以扫盘;要歌名、歌手、封面和时长,直接查 MediaStore,别自己解析 MP3 头。