传送到github看源码
下载apk试用 密码:rukn
很尴尬的一点就是大家没法听到音乐, 就只能看看图片.
我们需要先把Service添加进来, 再考虑使用MediaPlayer播放, 我们分步来说.
- 首先要有一个自定义接口, 这个接口中的方法都是要在服务中实现的, 然后要到Activity中使用的.
public interface IService {
//1. 定义接口IService, 添加调用函数, 调用MusicService中对应的函数
public void callPlayMusic(String path);
public void callPauseMusic();
public void callConMusic();
public void callSeekToPos(int pos);
}
- 然后来看Service中的实现, 自定义一个类, 继承Binder, 然后实现我们再接口中定义的方法.
/**
* 类MyBinder继承Binder实现接口IService
*/
private class MyBinder extends Binder implements IService {
//2. 定义类MyBinder继承Binder实现接口IService中的函数
@Override
public void callPlayMusic(String path) {
playMusic(path);
}
@Override
public void callPauseMusic() {
pauseMusic();
}
@Override
public void callConMusic() {
conMusic();
}
@Override
public void callSeekToPos(int pos) {
seekToPos(pos);
}
}
- 具体的实现就要涉及到MediaPlayer的使用了, 我们等下说, 先把Service绑定到Activity. 首先要返回一个自定义类的实例.
@Nullable
@Override
public IBinder onBind(Intent intent) {
//3. 返回自定义类MyBinder对象
return new MyBinder();
}
- 然后我们转到Activity来绑定服务
//4. 开启服务
Intent intent = new Intent(this, MusicService.class);
startService(intent);
//7. 绑定服务
MyConn myConn = new MyConn();
bindService(intent, myConn, BIND_AUTO_CREATE);
- 中间的MyConn又是一个自定义的类, 我们来看下实现. 之中要获取下IService对象, 以此调用定义的函数.
private class MyConn implements ServiceConnection {
//5. 定义类MyConn实现接口ServiceConnection
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//6. 获取IBinder对象, 以此调用暴露的函数
iService = (IService) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
然后服务就完成一个绑定了, 之后我们来说下MediaPlayer和SeekBar的使用. 无非就是播放, 暂停, 继续这些的实现. 具体的说明请移步官方文档
/**
* 播放音乐
*
* @param path 播放文件的路径
*/
public void playMusic(String path) {
Log.i(TAG, "playMusic");
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(path);
mediaPlayer.setLooping(true);
mediaPlayer.prepare();
mediaPlayer.start();
updateSeekBar();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 暂停播放音乐
*/
public void pauseMusic() {
Log.i(TAG, "pauseMusic");
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
/**
* 继续播放音乐
*/
public void conMusic() {
Log.i(TAG, "conMusic");
mediaPlayer.start();
}
读取文件系统肯定是要权限的, 可以查看我之前的文章一个Util带你获取Android6.0以上的读写sdcard权限
SeekBar这里用起来其实不难, 难就难在要从Service传数据到Activity. 这里我选用Handler, 当然你也可以用其它办法. 同样我们分步来说.
- 之前调用
mediaPlayer.start();
之后我调用了一个updateSeekBar();
, 现在来看看实现. 关键是要获取到音乐的总长度, 并且实时更新, 要实时更新的话, 我这里开了一个线程, 1s刷一次, 就不多说了.
/**
* 更新SeekBar
*/
private void updateSeekBar() {
//获取总时长
final int duration = mediaPlayer.getDuration();
//开启线程发送数据
new Thread() {
@Override
public void run() {
while (keepTrue) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int currentPosition = mediaPlayer.getCurrentPosition();
//发送数据给activity
Message message = Message.obtain();
Bundle bundle = new Bundle();
bundle.putInt("duration", duration);
bundle.putInt("currentPosition", currentPosition);
message.setData(bundle);
MainActivity.handler.sendMessage(message);
}
}
}.start();
}
- 然后回到Activity要接收发送的message. 接收到之后也完成的差不多了. 然后就是一个SeekBar的监听设置.
public static Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
Bundle data = msg.getData();
int duration = data.getInt("duration");
int currentPosition = data.getInt("currentPosition");
sb_progress.setMax(duration);
sb_progress.setProgress(currentPosition);
}
};
- 就是在放开拖动SeekBar的时候重新设置位置, 要注意的是, 函数seekToPos也是在Service中实现的.
//8. 设置进度条拖动事件
sb_progress.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
iService.callSeekToPos(seekBar.getProgress());
}
});
/**
* 设置SeekBar位置
*
* @param pos 当前位置
*/
public void seekToPos(int pos) {
mediaPlayer.seekTo(pos);
}
这样就完成啦! 喜欢就赶紧下载试试吧! 有意见或者建议也可以评论区哦.
传送到github看源码
下载apk试用 密码:rukn