如何用MediaPlayer写一个正经的音乐播放器
先贴上示例项目的Github地址:
Demo应用Play Store地址:
按照以下顺序介绍如何用MediaPlayer去构建一个基础的本地音乐播放器。
- 获取本地音乐数据;
- 构建PlayService,来执行音乐播放任务;
- 构建一个UI与PlayService的中间层——PlayManager,用来处理媒体文件的Playback生命周期;
- 在PlayManager中,加入处理意外情况的方式,所谓意外情况,例如耳机拔出、接到电话、其他播放器播放音乐等;
- 实现远程控制与PlayService保活,例如Notification与锁屏控制;
以上是已经实现的部分,以后再逐渐完善的有:
- 桌面Widget播放控件以及控制;
- 自定义播放列表支持;
- 视频播放支持;
- 远端媒体播放支持;
- 播放的可视化效果;
- 歌词支持;
- MediaCodec支持;
获取本地音乐数据
最快的获取本地音乐信息的方式,就是通过ContentProvider获取,我们先构建一个model类Song.java去表示音乐文件:
public class Song {
private String title, titleKey, artist, artistKey,
album, albumKey, displayName, mimeType, path;
private int id, albumId, artistId, duration, size, year, track;
private boolean isRingtone, isPodcast, isAlarm, isMusic, isNotification;
//private File mCoverFile;
private Album albumObj;
public Song (Bundle bundle) {
id = bundle.getInt(MediaStore.Audio.Media._ID);
title = bundle.getString(MediaStore.Audio.Media.TITLE);
titleKey = bundle.getString(MediaStore.Audio.Media.TITLE_KEY);
artist = bundle.getString(MediaStore.Audio.Media.ARTIST);
artistKey = bundle.getString(MediaStore.Audio.Media.ARTIST_KEY);
//mComposer = bundle.getString(MediaStore.Audio.Media.COMPOSER);
album = bundle.getString(MediaStore.Audio.Media.ALBUM);
albumKey = bundle.getString(MediaStore.Audio.Media.ALBUM_KEY);
displayName = bundle.getString(MediaStore.Audio.Media.DISPLAY_NAME);
year = bundle.getInt(MediaStore.Audio.Media.YEAR);
mimeType = bundle.getString(MediaStore.Audio.Media.MIME_TYPE);
path = bundle.getString(MediaStore.Audio.Media.DATA);
artistId = bundle.getInt(MediaStore.Audio.Media.ARTIST_ID);
albumId = bundle.getInt(MediaStore.Audio.Media.ALBUM_ID);
track = bundle.getInt(MediaStore.Audio.Media.TRACK);
duration = bundle.getInt(MediaStore.Audio.Media.DURATION);
size = bundle.getInt(MediaStore.Audio.Media.SIZE);
isRingtone = bundle.getInt(MediaStore.Audio.Media.IS_RINGTONE) == 1;
isPodcast = bundle.getInt(MediaStore.Audio.Media.IS_PODCAST) == 1;
isAlarm = bundle.getInt(MediaStore.Audio.Media.IS_ALARM) == 1;
isMusic = bundle.getInt(MediaStore.Audio.Media.IS_MUSIC) == 1;
isNotification = bundle.getInt(MediaStore.Audio.Media.IS_NOTIFICATION) == 1;
}
然后从ContentProvider中获得手机上的音乐文件:
public static List<Song> getAudioList(Context context) {
ContentResolver resolver = context.getContentResolver();
Cursor cursor = resolver.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
AUDIO_KEYS,
MediaStore.Audio.Media.IS_MUSIC + "=" + 1,
null,
null);
return getAudioList(cursor);
}
private static List<Song> getAudioList (Cursor cursor) {
List<Song> audioList = null;
if (cursor.getCount() > 0) {
audioList = new ArrayList<Song>();
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
Bundle bundle = new Bundle ();
for (int i = 0; i < AUDIO_KEYS.length; i++) {
final String key = AUDIO_KEYS[i];
final int columnIndex = cursor.getColumnIndex(key);
final int type = cursor.getType(columnIndex);
switch (type) {
case Cursor.FIELD_TYPE_BLOB:
break;
case Cursor.FIELD_TYPE_FLOAT:
float floatValue = cursor.getFloat(columnIndex);
bundle.putFloat(key, floatValue);
break;
case Cursor.FIELD_TYPE_INTEGER:
int intValue = cursor.getInt(columnIndex);
bundle.putInt(key, intValue);
break;
case Cursor.FIELD_TYPE_NULL:
break;
case Cursor.FIELD_TYPE_STRING:
String strValue = cursor.getString(columnIndex);
bundle.putString(key, strValue);
break;
}
}
Song audio = new Song(bund