MediaPlayer 是一款音乐播放器也是一款视频吧哦,这篇先介绍一个音乐播放器吧!
先看一下做好的效果吧!
这次介绍的功能点:
1、本地Sd卡中搜索音乐,并保存在List中
2、服务与Activity交互,可以用AIDL 、Binder,这次我们采用AIDL
3、SeekBar与音量关联同步 并修改时间
4、自定义TextView画歌词 并实现缓缓移动效果,并实现歌词与进度条同步
5、解析本地歌词
6、自定义通知栏
OK。先做一下准备工作。
首先我们来看一下MadiaPlayer的工作原理:
介绍之前大家先看一下这个图,然后看我的项目以后,回过头来再看一遍,会清晰好多。
在本地SD卡中查找音乐并且保存在List中:代码如下
/**
* 从本地sdcard获取数据
* 1、遍历sdcard,通过后缀名获取(效率比较慢)
* 2、通过内容提供者数据库中获取(Android系统内部有一个扫描器 ———— “媒体扫描器”,当手机开机完成后,或者sdcard插好后,
* 系媒体扫描器会发送一个广播开始工作,开始扫描sdcard,然后把数据存到数据库中,从而提供给第三方使用)
* todo 内容提供者:解决应用与应用共享数据,通过内容提供者暴露出来使用。
* 3、6.0动态权限
*/
public void getDataFromLocal() {
// 新建一个线程,比较耗时
new Thread(){
public void run(){
// 获取内容提供者
ContentResolver contentResolver = getContext().getContentResolver();
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String[] obj = {
MediaStore.Audio.Media.DISPLAY_NAME,//音频文件在sdcard的名称
MediaStore.Audio.Media.DURATION,//音频总时长
MediaStore.Audio.Media.SIZE,//音频的文件大小
MediaStore.Audio.Media.DATA,//音频的绝对地址(音频的播放地址)
MediaStore.Audio.Media.ARTIST,//歌曲的演唱者
};
// 查询方法。 参数1:uri. 参数2: 查询的指令
Cursor cursor = contentResolver.query(uri, obj, null, null, null);
if(cursor != null) {
while(cursor.moveToNext()) {
MediaItem mediaItem = new MediaItem();
mList.add(mediaItem);
// TODO: 2018/1/4 查询的0 1等位置是根据contentResolver.query()方法传入的obj参数获取的。
//音频的名称
String name = cursor.getString(0);
mediaItem.setName(name);
//音频的时长
long duration = cursor.getLong(1);
mediaItem.setDuration(duration);
//音频的文件大小
long size = cursor.getLong(2);
mediaItem.setSize(size);
//音频的播放地址
String data = cursor.getString(3);
mediaItem.setData(data);
//艺术家
String artist = cursor.getString(4);
mediaItem.setArtist(artist);
}
cursor.close();
}
// 更新UI
handler.sendEmptyMessage(MAG_HANDLER);
}
}.start();
}
/**
* 6.0动态获取sd卡权限
*/
public boolean isGrantExternalRW(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && activity.checkSelfPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
activity.requestPermissions(new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, 1);
return false;
}
return true;
}
创建AIDL让服务与Activity通信:
1、创建服务
2、在清单文件中添加:
<service android:name=".serveice.MusicPlayerService">
<intent-filter>
<action android:name="com.atguigu.mobileplayer_OPENAUDIO" />
</intent-filter>
</service>
3、在工程目录下,选中main 然后右键创建AIDL文件,此文件就是声明方法,暴露的方法让Activity调用,从而Aidl在调用服务中的方法。AIDL可以说是一个代理类。完成服务与页面的交互:
我把所有的方法都写出来了,方便后期大家查询
interface IMusicPlayerService {
/**
* 根据位置打开对应的音频文件
* @param position
*/
void openAudio(int position);
/**
* 播放音乐
*/
void start();
/**
* 播暂停音乐
*/
void pause();
/**
* 停止
*/
void stop();
/**
* 得到当前的播放进度
* @return
*/
int getCurrentPosition();
/**
* 得到当前音频的总时长
* @return
*/
int getDuration();
/**
* 得到艺术家
* @return
*/
String getArtist();
/**
* 得到歌曲名字
* @return
*/
String getName();
/**
* 得到歌曲播放的路径
* @return
*/
String getAudioPath();
/**
* 播放下一个视频
*/
void next();
/**
* 播放上一个视频
*/
void pre();
/**
* 设置播放模式
* @param playmode
*/
void setPlayMode(int playmode);
/**
* 得到播放模式
* @return
*/
int getPlayMode();
/**
* 是否正在播放
*/
boolean isPlaying();
/**
拖动音频
*/
void seekTo(int position);
int getAudioSessionId();
}
4、在服务中创建AIDL,然后AIDL调用服务的方法。如下:
我这里只是粘贴了一部分方法,全部的方法跟AIDL声明的方法一样。 最重要的不要忘记在服务中把stub返回去。 这样通过AIDL一个代理类就可以了
@Override
public IBinder onBind(Intent intent) {
return stub;
}
/**
* 创建AIDL 服务代理类, 通过代理类与服务交互
*/
private IMusicPlayerService.Stub stub = new IMusicPlayerService.Stub(){
/** 创建服务*/
MusicPlayerService service = MusicPlayerService.this;
@Override