Github地址:https://github.com/boybeak/BeMusic
以前写过很多次音乐播放器,但是总有一些问题出现,例如:
1,音乐长时间播放问题(即便是放在service中去播放,依然会被杀死);
2,音乐的播放进度如何掌握?(如何利用mediaplayer.getCurrentPosition()来有效的通知界面变更进度?);
3,在我以往的经验中,音乐播放完毕下一曲时候,经常出现当前音乐播放还差几秒钟的时候就下一曲了的情况。
从网上找到教程中,通常都是一个播放器的demo,简单的直接把MediaPlayer放在了一个Activity中去操作,稍有良心的教程把MediaPlayer放在了Servic中,但是这是远远不够的。
最好的教程还是谷歌官方的Training和API Guides,尽管很久以前就简单粗暴的读过有关service的文档,但是,古人都说温故而知新嘛,经过这次温故,对比以前的代码经验,觉得可以有更好的方式来实现一个音乐播放器。遂决定重新写一个音乐播放器。
如果有大神有更好 方案,还望知会我。
注意:这篇文章,不适合对MediaPlayer不了解的同学,假定看这篇文章的,都是已经会初步使用Service的同学。
一,音乐列表的读取。
关于音乐列表的读取,不同的音乐播放器都会有不同的方案,有的是有多重方案并用。例如说,全盘扫描音乐格式文件等,但是Android本身有媒体库,可以读取本地媒体库的数据,来快速获知设备上的音乐。
首先我封装了一个Audio类来存储读取的音频信息。
public class Audio {
private String mTitle,
mTitleKey,
mArtist,
mArtistKey,
mComposer,
mAlbum,
mAlbumKey,
mDisplayName,
mMimeType,
mPath;
private int mId,
mArtistId,
mAlbumId,
mYear,
mTrack;
private int mDuration = 0,
mSize = 0;
private boolean isRingtone = false,
isPodcast = false,
isAlarm = false,
isMusic = false,
isNotification = false;
public Audio (Bundle bundle) {
mId = bundle.getInt(MediaStore.Audio.Media._ID);
mTitle = bundle.getString(MediaStore.Audio.Media.TITLE);
mTitleKey = bundle.getString(MediaStore.Audio.Media.TITLE_KEY);
mArtist = bundle.getString(MediaStore.Audio.Media.ARTIST);
mArtistKey = bundle.getString(MediaStore.Audio.Media.ARTIST_KEY);
mComposer = bundle.getString(MediaStore.Audio.Media.COMPOSER);
mAlbum = bundle.getString(MediaStore.Audio.Media.ALBUM);
mAlbumKey = bundle.getString(MediaStore.Audio.Media.ALBUM_KEY);
mDisplayName = bundle.getString(MediaStore.Audio.Media.DISPLAY_NAME);
mYear = bundle.getInt(MediaStore.Audio.Media.YEAR);
mMimeType = bundle.getString(MediaStore.Audio.Media.MIME_TYPE);
mPath = bundle.getString(MediaStore.Audio.Media.DATA);
mArtistId = bundle.getInt(MediaStore.Audio.Media.ARTIST_ID);
mAlbumId = bundle.getInt(MediaStore.Audio.Media.ALBUM_ID);
mTrack = bundle.getInt(MediaStore.Audio.Media.TRACK);
mDuration = bundle.getInt(MediaStore.Audio.Media.DURATION);
mSize = 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;
}
public int getId() {
return mId;
}
public String getMimeType () {
return mMimeType;
}
public int getDuration () {
return mDuration;
}
public int getSize () {
return mSize;
}
public boolean isRingtone () {
return isRingtone;
}
public boolean isPodcast () {
return isPodcast;
}
public boolean isAlarm () {
return isAlarm;
}
public boolean isMusic () {
return isMusic;
}
public boolean isNotification () {
return isNotification;
}
public String getTitle () {
return mTitle;
}
public String getTitleKey () {
return mTitleKey;
}
public String getArtist () {
return mArtist;
}
public int getArtistId () {
return mArtistId;
}
public String getArtistKey () {
return mArtistKey;
}
public String getComposer () {
return mComposer;
}
public String getAlbum () {
return mAlbum;
}
public int getAlbumId () {
return mAlbumId;
}
public String getAlbumKey () {
return mAlbumKey;
}
public String getDisplayName () {
return mDisplayName;
}
public int getYear () {
return mYear;
}
public int getTrack () {
return mTrack;
}
public String getPath () {
return mPath;
}
}
以上类来封装音乐媒体信息,一些变量看名字也能看出来是什么,例如说title,duration此类,无非就是歌曲名称,时长之类的信息,有些变量名字单词认识,但是并不知道干什么用,其实我也不知道是什么信息,虽然打印出来过,但是并不懂到底哪里能用到,反正一股脑都读出来了先,以后再打印输出看看都是些什么。
其次,一个读取媒体音频的方法:
public class MediaUtils {
public static final String[] AUDIO_KEYS = new String[]{
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.TITLE_KEY,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.ARTIST_ID,
MediaStore.Audio.Media.ARTIST_KEY,
MediaStore.Audio.Media.COMPOSER,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media.ALBUM_KEY,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.SIZE,
MediaStore.Audio.Media.YEAR,
MediaStore.Audio.Media.TRACK,
MediaStore.Audio.Media.IS_RINGTONE,
MediaStore.Audio.Media.IS_PODCAST,
MediaStore.Audio.Media.IS_ALARM,
MediaStore.Audio.Media.IS_MUSIC,
MediaStore.Audio.Media.IS_NOTIFICATION,
MediaStore.Audio.Media.MIME_TYPE,
MediaStore.Audio.Media.DATA
};
public static List<Audio> getAudioList(Context context) {
List<Audio> audioList = new ArrayList<Audio>();
ContentResolver resolver = context.getContentResolver();
Cursor cursor = resolver.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
AUDIO_KEYS,
null,
null,
null);
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;
}
}
Audio audio = new Audio (bundle);
audioList.add(audio);
}
cursor.close();
return audioList;
}
}
如此返回一个Audio的List,现在我们可以用这个List做一个列表展示。