花了一段时间写了一个比较简单基础的音乐播放器,实现功能如下:
1. 获取SD卡中的音频文件
2. 后台播放音乐
3. 切换播放模式
4. 切换上一首,下一首
5. 播放进度条,快进快退
6. 拔出耳机暂停播放
7. 如果有其他音乐播放器播放音乐,则暂停播放
功能看起来比较少,也很简单,但是要把这些所有功能整合一块还真有点不容易,下面,记录一下做的过程。
一. 首先来看获取sd卡中的音频文件:
我们都知道,Android系统一般有一个数据库,这个库中存放着我们联系人,短信,音视频文件,图片等数据,而Android系统又把对这些数据的操作都封装成了相应的类,一般通过ContentResolver就可以操作这个数据库。今天需要读取音频文件,所以需要用到MediaStore这个类来获取音频数据,下边是写的一个获取sd卡音频文件的方法,最后会将数据封装成List返回(Music是一个实体类,存储音乐的一些信息,比较简单,这个就不贴代码了),如下:
public static List<Music> getMusicFile(Context context) {
//生成动态数组,并且转载数据
List<Music> MusicFiles = new ArrayList<Music>();
//查询媒体数据库
ContentResolver resolver = context.getContentResolver();
Cursor cursor = resolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
//遍历媒体数据库
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
//歌曲编号
int id = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID));
//歌曲标题
String title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
//歌曲的专辑名:MediaStore.Audio.Media.ALBUM
String album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
//歌曲的歌手名: MediaStore.Audio.Media.ARTIST
String artist = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
//歌曲文件的路径 :MediaStore.Audio.Media.DATA
String url = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
//歌曲的总播放时长 :MediaStore.Audio.Media.DURATION
int duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));
//歌曲文件的大小 :MediaStore.Audio.Media.SIZE
long size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));
if (size > 1024 * 800) {//大于800K
if (title.equals("<unknown>") || title.equals("")) {
title = "未知";
}
if ("<unknown>".equals(artist) || "".equals(artist)) {
artist = "未知";
}
Music music = new Music(id, title, artist,
url, album, duration, size);
MusicFiles.add(music);
}
cursor.moveToNext();
}
}
return MusicFiles;
}
可以看到,我们可以通过MediaStore拿到关于音乐文件的标题,歌手名,专辑,时间等信息,这个信息都存在Music中。我们只需要写一个activity,用listView将这些数据显示出来就好。
LocalMusicListActivity.java:
public class LocalMusicListActivity extends BaseActivty {
private ListView mLvLocalMusic;
private LocalMusicListAdapter mAdapter;
private List<Music> mMusicDatas;
private Context mContext = this;
@Override
protected void setLayout() {
setContentView(R.layout.activity_local_music_list);
mRight.setVisibility(View.INVISIBLE);
mTitle.setText("本地歌曲");
}
@Override
protected void initView() {
mLvLocalMusic = (ListView) findViewById(R.id.local_music_list);
mMusicDatas = new ArrayList<Music>();
mMusicDatas = Utils.getMusicFile(mContext);
mAdapter = new LocalMusicListAdapter(this);
mAdapter.resetData(mMusicDatas);
mLvLocalMusic.setAdapter(mAdapter);
}
@Override
protected void setListener() {
}
}
到此,音频文件的读取和显示就完了,效果图如下:
二. 主界面的简介(MainActivity.java):
主界面我们主要显示的有歌曲名,已播放的时间,总播放时间,进度条,播放模式按钮,播放按钮,上一首,下一首按钮以及列表按钮和界面背景,效果图如下(这里就不贴布局代码了,后边会给出源码):
当然,在MainActivity内部需要有一个广播接收器来接受服务发过来的广播
class MusicReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
int activitySignal = bundle.getInt(Contants.ACTIVITY_SIGNAL, -1);
switch (activitySignal) {
case Contants.UPDATE_PLAY_ACTIVITY:
mMusicState = bundle.getInt(Contants.MUSIC_STATE);
mPlayingMusic = (Music) bundle.getSerializable(Contants.CURRENT_MUSIC);
mMusicMode = bundle.getInt(Contants.MUSIC_MODE);
mMusicPlayPosition = bundle.getInt(Contants.MUSIC_PLAY_POS, 0);
updateMusicInfo(mMusicMode, mMusicPlayPosition);
break;
}
}
}
服务发过来的任何广播都是为了更新界面,所以我们把需要更新的数据都封装在一起,不管是界面的那块需要更新,都会更新整个界面所有信息。
三. 服务的简单介绍(MusicServer.java):
既然服务的主要任务是播放音乐,那么服务中就需要一个MediaPlayer对象来播放音乐,还需要获取到sd卡中的音频文件,并且记录当前正在播放的音乐和位置,MusicServer的成员变量如下:
private MediaPlayer mMediaPlayer; //播放音乐对象
private ServiceReceiver mReceiver; //广播接收器(接收界面发来的广播)
private Bundle mBundle;
private List<Music> mMusicFiles; //sd卡的音频文件集合
private Music mPlayingMusic; //当前正在播放的音乐
private int mMusicPosition = 0; //当前播放音乐在集合中的位置
private int mMusicPlayPos = 0; //当前音乐的播放位置
private int mMusicState = Contants.STOP; //音乐播放状态
private int mMusicMode = Contants.MODE_MUSIC_LIST_ORDER; //播放模式
private PowerManager.WakeLock mWakeLock; //电源锁对象
private Timer mTimer; //定时器
private boolean isSeekbarChanged = false; //进度条滑动标识
private AudioManager mAmanager;
MyOnAudioFocusChangeListener mListener;
当然,因为服务和界面是通过Broadcast进行通信的,所以MusicServer中肯定也要有一个接收器来接收服务发过来的广播:
class ServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
}
}
广播接收器需要在onCreate方法和onDestroy方法中注册和解除。接下来需要初始化成员变量。
好了,此篇就介绍这些,下篇介绍主界面和服务初始化时需要做的事情