本文主要是介绍Android_播放器_利用Service通过MediaPlayer播放歌曲并完成歌词同步绘制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
本博文为子墨原创,转载请注明出处!
http://blog.csdn.net/zimo2013/article/details/16849695
1.示意图
2. 代码实现
/*** MainActivity.java* @author zimo2013* @see http://blog.csdn.net/zimo2013**/ public class MainActivity extends Activity implements OnClickListener,OnSeekBarChangeListener {private LrcSurfaceView surfaceView;private Button btPlay;private Button btPause;private Button btStop;private SeekBar bar;private PlayerConn conn;private IMyBinder binder;private boolean isDrag; //进度条是否正在拖拽private List<LrcInfo> list;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initViews();list = new ArrayList<LrcInfo>();conn = new PlayerConn();Intent intent = new Intent(this, PlayService.class);bindService(intent, conn, BIND_AUTO_CREATE);bar.setOnSeekBarChangeListener(this);btPlay.setOnClickListener(this);btPause.setOnClickListener(this);btStop.setOnClickListener(this);parseLrc();}private void initViews() {surfaceView = (LrcSurfaceView) findViewById(R.id.lrc);btPlay = (Button) findViewById(R.id.bt_play);btPause = (Button) findViewById(R.id.bt_pause);btStop = (Button) findViewById(R.id.bt_stop);bar = (SeekBar) findViewById(R.id.bar);}/*** 歌词解析*/public void parseLrc() {BufferedReader bufr = null;try {if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {bufr = new BufferedReader(new InputStreamReader(new FileInputStream(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/music.lrc")));String data = null;//添加第一条以歌名开头的歌词list.add(new LrcInfo(0, "music"));// "[00:09.77]Why did the writer complain to the people behind him?"Pattern pattern = Pattern.compile("\\[(\\d{2}):(\\d{2}.\\d{2,3})\\](.*)");while ((data = bufr.readLine()) != null) {Matcher matcher = pattern.matcher(data);while (matcher.find()) {int minute = Integer.parseInt(matcher.group(1));//分钟 00 float second = Float.parseFloat(matcher.group(2));//秒 09.77list.add(new LrcInfo((int) ((minute * 60 + second) * 1000), matcher.group(3)));}}//为surfaceView设定歌词surfaceView.setList(list);}} catch (Exception e) {e.printStackTrace();}finally{if(bufr != null){try {bufr.close();} catch (IOException e) {e.printStackTrace();}}}}@Overridepublic void onClick(View v) {Intent intent = new Intent(this, PlayService.class);if (btPlay == v) {intent.setAction(PlayService.ACTION_PLAY);} else if (btPause == v) {intent.setAction(PlayService.ACTION_PAUSE);} else if (btStop == v) {intent.setAction(PlayService.ACTION_STOP);}startService(intent);}private class PlayerConn implements ServiceConnection {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {binder = (IMyBinder) service;binder.setHandler(handler); //设定handler}@Overridepublic void onServiceDisconnected(ComponentName name) {}}private Handler handler = new Handler() {public void handleMessage(Message msg) {System.out.println("msg what:" + msg.what + " arg1:" + msg.arg1);switch (msg.what) {case PlayService.WHAT_DURATION:bar.setMax(msg.arg1);break;case PlayService.WHAT_CURRENT:if (!isDrag) {//更新进度条以及歌词bar.setProgress(msg.arg1);surfaceView.update(msg.arg1);}break;}}};@Overridepublic void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {if(fromUser){surfaceView.update(bar.getProgress());//更新歌词}}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {//移除所有未处理的消息handler.removeMessages(PlayService.WHAT_CURRENT);isDrag = true;}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {//拖拽完成,更新Intent intent = new Intent(this, PlayService.class);intent.setAction(PlayService.ACTION_PLAY);intent.putExtra("progress", bar.getProgress());startService(intent);isDrag = false;}@Overrideprotected void onDestroy() {super.onDestroy();//解除服务unbindService(conn);} }
/*** PlayService.java* @author zimo2013* @see http://blog.csdn.net/zimo2013**/ public class PlayService extends Service {public static final String ACTION_PLAY = "play";public static final String ACTION_PAUSE = "pause";public static final String ACTION_STOP = "stop";public static final int WHAT_CURRENT = 1;public static final int WHAT_DURATION = 2;private MediaPlayer player;private Handler handler;private IMyBinder binder;private int progress;@Overridepublic void onCreate() {super.onCreate();binder = new MyBinder();}@Overridepublic IBinder onBind(Intent intent) {return (IBinder) binder;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {String action = intent.getAction();if (ACTION_PLAY.equals(action)) {progress = intent.getIntExtra("progress", 0);toPlay(progress);} else if (ACTION_PAUSE.equals(action)) {pause();} else if (ACTION_STOP.equals(action)) {stop();}return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();if(player != null){player.release(); //是否资源player = null; //置空,拷贝GC回收}}/*** 将要播放* @param pos*/private void toPlay(int pos) {checkMediaPlayer();if (state == PlayerState.Initialized) {state = PlayerState.Preparing;player.prepareAsync();} else {play(pos);}}/*** 实际播放音乐* @param pos*/private void play(int pos) {if (state == PlayerState.Started || state == PlayerState.Prepared|| state == PlayerState.Paused|| state == PlayerState.PlaybackCompleted) {if (state != PlayerState.Paused) {player.seekTo(pos);}player.start();state = PlayerState.Started;new Thread() {public void run() {// updateUI();while (state == PlayerState.Started) {send(WHAT_CURRENT, player.getCurrentPosition());try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}}.start();} else {show("播放异常");}}/*** 暂停播放*/private void pause() {if (state == PlayerState.Started) {player.pause();state = PlayerState.Paused;} else if (state == PlayerState.Paused) {show("播放已经暂停,现不需要再暂停!");} else {show("暂停异常");}}/*** 停止播放*/private void stop() {if (state == PlayerState.Started || state == PlayerState.Prepared|| state == PlayerState.Paused|| state == PlayerState.PlaybackCompleted) {player.release(); //是否资源player = null; //置空,拷贝GC回收state = PlayerState.End;} else {show("停止异常");}}/*** 发送消息,用于更新ui* @param what* @param value*/private void send(int what, int value) {// 更新进度条Message msg = handler.obtainMessage();msg.what = what;msg.arg1 = value;handler.sendMessage(msg);}/*** 检查MediaPlayer对象,如果不存在则应该创建,并完成相关初始化*/private void checkMediaPlayer() {if (player == null) {// 完成多媒体的初始化player = new MediaPlayer();state = PlayerState.Idle;player.setAudioStreamType(AudioManager.STREAM_MUSIC);// 判断SDcard正常挂载if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {try {player.setDataSource(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/music.mp3");state = PlayerState.Initialized;//异步准备player.setOnPreparedListener(new OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mp) {state = PlayerState.Prepared;// 设定进度条的max值send(WHAT_DURATION, player.getDuration());// 准备完成play(progress);}});//播放完成player.setOnCompletionListener(new OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {state = PlayerState.PlaybackCompleted;// 播放完成play(0);show("已经播放完成,现在正在重新播放");}});} catch (Exception e) {e.printStackTrace();}}}}/*** 自定义MyBinder* @author Administrator**/private class MyBinder extends Binder implements IMyBinder {@Overridepublic void setHandler(Handler handler) {PlayService.this.handler = handler;}}/*** 弹出吐司* @param info*/public void show(String info) {Toast.makeText(getApplicationContext(), info, 0).show();}private PlayerState state = PlayerState.Idle;/*** 播放器的播放状态枚举* @author Administrator**/private enum PlayerState {Idle, Initialized, Preparing, Prepared, Started, Stopped, Paused, End, PlaybackCompleted,} }
/*** LrcSurfaceView.java* @author zimo2013* @see http://blog.csdn.net/zimo2013**/ public class LrcSurfaceView extends SurfaceView {private SurfaceHolder holder;private List<LrcInfo> list;private boolean isCreated;private int mWidth;private int mHeight;private int pos = 0;private Paint paintNew;private Paint paintOld;private int current;private ExecutorService thread;private Runnable runnable;public LrcSurfaceView(Context context) {this(context, null, 0);}public LrcSurfaceView(Context context, AttributeSet attrs) {this(context, attrs, 0);this.getHolder();}public LrcSurfaceView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);holder = getHolder();holder.addCallback(new LrcCallBack());// 线程池thread = Executors.newSingleThreadExecutor();runnable = new LrcUpdateRunnable();// 创建2种画笔对象paintNew = new Paint();paintNew.setTextSize(20);paintNew.setTextAlign(Paint.Align.CENTER);paintNew.setColor(Color.YELLOW);paintOld = new Paint();paintOld.setTextSize(15);paintOld.setTextAlign(Paint.Align.CENTER);//居中显示paintOld.setColor(Color.WHITE);}/*** 为surfaceView 设定歌词* * @param list*/public void setList(List<LrcInfo> list) {Collections.sort(list); // 歌词排序,从前往后this.list = list;}/*** 更新歌词信息* * @param current*/public void update(int current) {if (isCreated && list != null && list.size() > 0) {// 如果surfaceView对应已经被创建或者存在歌词this.current = current;thread.execute(runnable); // 线程池更新歌词信息}}private class LrcUpdateRunnable implements Runnable {@Overridepublic void run() {pos = 0;// 默认从第一条歌词开始寻找Canvas canvas = holder.lockCanvas();canvas.drawColor(Color.BLACK);while (true) {if (pos == list.size() - 1) {break;}if (current >= list.get(pos).startTime && current < list.get(pos + 1).startTime) {break;}pos++;}//Surface可以直接操作UIif (pos != 0) {// 上一条已经播放歌词canvas.drawText(list.get(pos - 1).lrc, mWidth / 2, mHeight / 2 - 50, paintOld);}// 当前正在播放歌词canvas.drawText(list.get(pos).lrc, mWidth / 2, mHeight / 2, paintNew);// 下一条需要播放歌词if (pos != list.size() - 1) {canvas.drawText(list.get(pos + 1).lrc, mWidth / 2, mHeight / 2 + 50, paintOld);}// 接触锁定并提交holder.unlockCanvasAndPost(canvas);}}private class LrcCallBack implements SurfaceHolder.Callback {@Overridepublic void surfaceCreated(SurfaceHolder holder) {}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {isCreated = true;mHeight = height;mWidth = width;}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}}}
/*** IMyBinder.java* @author zimo2013* @see http://blog.csdn.net/zimo2013**/ public interface IMyBinder {void setHandler(Handler handler); }
这篇关于Android_播放器_利用Service通过MediaPlayer播放歌曲并完成歌词同步绘制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!