最近开始学习音频相关。所以,很想自己做一个音乐播放器,于是,花了一天学习,将播放器的基本功能实现了出来。我觉得学习知识点还是蛮多的,所以写篇博客总结一下关于一个音乐播放器实现的逻辑。希望这篇博文对你的学习和生活有所帮助。效果图:

**实现逻辑**

在市面上的音乐播放app,即时你关了。那么一样会在后台播放,所以播放的逻辑应该写在Service中。并且能够实现Service和Activity之间进行通信。那么Service是四大组件之一,所以在使用的时候一定不要忘了在配置文件中声明一下。

     <service android:name="com.yakir.services.MusicService">

        </service>

我们需要重写Service中的三个方法,onCreate(),onStartCommand(),onDestroy()。

onCreate():Service第一次启动的时候调用这个方法,可以做一些变量的初始化。

onStartCommand():Service每一次启动的时候调用这个方法,可以在此方法写一些业务逻辑。

onDestroy():Service销毁的时候调用,用于释放资源。

接下来,如果需要播放一个音乐文件,可以使用安卓自带的播放器MediaPlayer,将播放逻辑封装起来:

    //开始
public void start(String path) {
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(path);
mediaPlayer.prepare();
mediaPlayer.start();
MediaUtils.currentState= Constants.PLAY_START;
} catch (IOException e) {
e.printStackTrace();
}
}
//暂停
public void pause (){
if (mediaPlayer!=null&&mediaPlayer.isPlaying()) {
mediaPlayer.pause();
MediaUtils.currentState=Constants.PLAY_PAUSE;
}
}
//继续播放
public void continuePlay() {
if (mediaPlayer!=null&&!mediaPlayer.isPlaying()) {
mediaPlayer.start();
MediaUtils.currentState= Constants.PLAY_START;
}
}
//停止播放
public void stop() {
if (mediaPlayer!=null) {
mediaPlayer.stop();
MediaUtils.currentState=Constants.PLAY_STOP;
}
}

我们知道,UI是写在Activity中的,那么就涉及到Activity与Service之间进行通信,他们之间通信的方式有5种,这里我是用了Intent,调用startService()进行通信,

同时让Intent携带一组键值对数据,与Service端进行匹配。

Activity:

   private void startMusicService(String option,String path) {
Intent intentService = new Intent(MainActivity.this, MusicService.class);
intentService.putExtra("option", option);
intentService.putExtra("messenger",new Messenger(handler));
intentService.putExtra("path", path);
startService(intentService);
}
private void startMusicService(String option) {
Intent intentService = new Intent(MainActivity.this, MusicService.class);
intentService.putExtra("option", option);
intentService.putExtra("messenger",new Messenger(handler));
startService(intentService);
}
private void startMusicService(String option,int progress) {
Intent intentService = new Intent(MainActivity.this, MusicService.class);
intentService.putExtra("option", option);
intentService.putExtra("progress",progress);
intentService.putExtra("messenger",new Messenger(handler));
startService(intentService);
}

Service:

    @Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("thread",Thread.currentThread().getName() );
String option=intent.getStringExtra("option");
if (messenger==null) {
messenger = (Messenger) intent.getExtras().get("messenger");
}
if ("开始".equals(option)) {
start(intent.getStringExtra("path"));
} else if ("暂停".equals(option)) {
pause();
} else if ("继续".equals(option)) {
continuePlay();
} else if ("停止".equals(option)) {
stop();
} else if ("跳转".equals(option)) {
seekPlay(intent.getIntExtra("progress",-1));
}
return super.onStartCommand(intent, flags, startId);
}

这样,就实现了两者之间的通信,接下来,当我点击下一首的时候,那么下一个item的文字高亮,并且播放下一首歌。

先从系统中拿到所有的音频数据:

   public static void getSongList (Context context) {
musicBeanList.clear();
Uri uri= MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor cursor=context.getContentResolver().query(uri,
new String[]{
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.DATA},null,null,null);
while (cursor.moveToNext()) {
musicBeanList.add(new MusicBean(
cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE)),
cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST)),
cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA))));
}
}

通过内容提供者,拿到系统的所有音频数据,以及音频的相关信息。DATA就是音频路径,拿到音频路径后就可以根据现实位置进行播放切换了。(这里很简单,不细说)

处理文字高亮:

我们需要知道当前的item位置和下一个item位置,当点击下一首歌曲,下个位置高亮,其他位置不亮。所以,需要我们定义一个常量记录当前位置,并且,当点击下一首,常量增加,上一首,常量减少。

   case R.id.ib_bottom_last:
setColor(Color.BLUE);
MediaUtils.currentPosition--;
setColor(Color.RED);
startMusicService("开始",MediaUtils.musicBeanList.get(MediaUtils.currentPosition).path);
imgBottomPlay.setImageResource(R.drawable.appwidget_pause);
break;
case R.id.ib_bottom_next:
setColor(Color.BLUE);
MediaUtils.currentPosition++;
setColor(Color.RED);
startMusicService("开始",MediaUtils.musicBeanList.get(MediaUtils.currentPosition).path);
imgBottomPlay.setImageResource(R.drawable.appwidget_pause);
break;

需要在改变颜色时做一下逻辑处理:

当到最后一个item时点击下一个高亮变为第一个,当位于第一个时,点击上一首,高亮位于最后一个位置。

  private void setColor(int color) {
if (MediaUtils.currentPosition==MediaUtils.musicBeanList.size()) {
MediaUtils.currentPosition=0;
}
if (MediaUtils.currentPosition==-1) {
MediaUtils.currentPosition=MediaUtils.musicBeanList.size()-1;
}
TextView textView= (TextView) songList.findViewWithTag(MediaUtils.currentPosition);
if (textView!=null) {
textView.setTextColor(color);
} }

接下来,需要实现一个更随音乐播放进度的进度条,这就需要实现Service向Activity的通信,可以通过消息机制,让Service发送消息给Activity,将播放信息传递给Activity.

拿着这个Intent传一个信使(Messager).

intentService.putExtra("messenger",new Messenger(handler));

从而Service:

                                Message message=Message.obtain();
message.arg1=currentPostion;
message.arg2=duration;
message.what=Constants.MUSIC_PREPARE;
messenger.send(message);

Activity再处理:

    private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Constants.MUSIC_PREPARE:
int curduration=msg.arg1;
int totalduration=msg.arg2;
tv_curduration.setText(MediaUtils.duration2Str(curduration));
tv_totalduration.setText(MediaUtils.duration2Str(totalduration));
sk_duration.setMax(totalduration);
sk_duration.setProgress(curduration);
break;
}
}
};

在SeekBar中设置监听,当拖动停止时把当前进度传给Service,让音乐就当前位置播放:

   sk_duration.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) {
sk_duration.setProgress(seekBar.getProgress());
startMusicService("跳转",seekBar.getProgress());
}
});

同时,我们需要注意到一个情况,当启动电话时,音乐应该是停止状态,可以通过AudioManager获得音频焦点,当焦点失去时,音乐也应该停止:

     AudioManager audioManager= (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.requestAudioFocus(new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
mediaPlayer.start();
mediaPlayer.setVolume(1.f,2.0f);
break;
case AudioManager.AUDIOFOCUS_LOSS:
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer=null;
break;
case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
if (mediaPlayer.isPlaying());
mediaPlayer.pause();
break;
} }
},AudioManager.STREAM_MUSIC,AudioManager.AUDIOFOCUS_GAIN);

好了,这样一个简单的音乐播放器就完成了,虽然说代码不是很困难,但是还是有很多知识点,比如Activity中Service中的通信,以及ListView相关,还有程序的逻辑性,所以我把几个重要的点总结了一下。希望这篇博文对你的生活和学习有所帮助,如果有什么疑问可以在下方留言,如果你想要源码,可以私聊我~

Android开发实战之简单音乐播放器的更多相关文章

  1. Android实现简单音乐播放器(MediaPlayer)

    Android实现简单音乐播放器(MediaPlayer) 开发工具:Andorid Studio 1.3 运行环境:Android 4.4 KitKat 工程内容 实现一个简单的音乐播放器,要求功能 ...

  2. Android实现简单音乐播放器(startService和bindService后台运行程序)

    Android实现简单音乐播放器(MediaPlayer) 开发工具:Andorid Studio 1.3运行环境:Android 4.4 KitKat 工程内容 实现一个简单的音乐播放器,要求功能有 ...

  3. Android 实现简单音乐播放器(二)

    在Android 实现简单音乐播放器(一)中,我介绍了MusicPlayer的页面设计. 现在,我简单总结一些功能实现过程中的要点和有趣的细节,结合MainActivity.java代码进行说明(写出 ...

  4. Android 实现简单音乐播放器(一)

    今天掐指一算,学习Android长达近两个月了,今天开始,对过去一段时间的学习收获以及遇到的疑难杂症做一些总结. 简单音乐播放器是我自己完成的第一个功能较为完整的APP,可以说是我的Android学习 ...

  5. Android——简单音乐播放器

    使用MediaPlayer做的简单音乐播放器,更多内容请到百度经验查看   http://jingyan.baidu.com/article/60ccbceb63452364cab197f1.html ...

  6. Android应用--简、美音乐播放器增加音量控制

    Android应用--简.美音乐播放器增加音量控制 2013年6月26日简.美音乐播放器继续完善中.. 题外话:上一篇博客是在6月11号发的,那篇博客似乎有点问题,可能是因为代码结构有点乱的原因,很难 ...

  7. Android应用--简、美音乐播放器获取专辑图片(自定义列表适配器)

    Android应用--简.美音乐播放器获取专辑图片(自定义列表适配器) 2013年7月3日简.美音乐播放器开发 第二阶段已增加功能: 1.歌词滚动显示 2.来电监听 3.音量控制 4.左右滑动切换歌词 ...

  8. html5 简单音乐播放器

    html5 简单音乐播放器 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> < ...

  9. iOS之基于FreeStreamer的简单音乐播放器(模仿QQ音乐)

    代码地址如下:http://www.demodashi.com/demo/11944.html 天道酬勤 前言 作为一名iOS开发者,每当使用APP的时候,总难免会情不自禁的去想想,这个怎么做的?该怎 ...

随机推荐

  1. psoc4的capsense总结

    psoc4的capsense算是个比较实用的东西,触摸按键,显得有点高大上,呵呵.今天试用了一下,对照着数据手册,现在总结一下. 1,先说原理,官方做文档的时候应该把原理讲一下,不要上来就讲怎么用,怎 ...

  2. 【DUBBO】dubbo架构详解(转载)

    转载地址:http://shiyanjun.cn/archives/325.html Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解 ...

  3. 如何点焊过的镍片再次焊接到 PCBA 上?

    如何将点焊过的镍片再次焊接到 PCBA 上? 在 PCBA 上贴了镍片再点焊,这样的制造工艺可以大大减少人工处理,提高生产通过率. 由于种种原因,有些机器可能有故障需要维修,而且电池又需要拆下来,才能 ...

  4. 15.Python实现识别登录验证码(入门)

    1.若想识别登录验证码,需要安装:Tesseract-OCR,其下载地址为:http://jaist.dl.sourceforge.net/project/tesseract-ocr-alt/tess ...

  5. CentOS 7安装chroot Named

    一 安装相关软件 yum install bind-chroot bind -y 二 复制生成文件 cp -R /usr/share/doc/bind-*/sample/var/named/* /va ...

  6. 使用Apache POI操作Excel文件---在已有的Excel文件中插入一行新的数据

    package org.test; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundEx ...

  7. 兼顾FPGA和单片机

    当今,FPGA和单片机的应用非常广泛,在有FPGA知识的基础上,笔者认为可以把FPGA作为主要的学习目标,单片机作为辅助技能.其实二者是相互促进的.不管是FPGA还是单片机的开发其实都是基于较强的逻辑 ...

  8. java代码---I/O文件内容复制

    总结:主要是弄清输入流,输出流 输入流和输出流都是针对程序而言,把文件内容读取到程序是输入流 从程序把内容写入文件是输出流 package com.a.b; import java.io.*; imp ...

  9. ESXI5-WIN2008R2安装域控以及额外域笔记

    每次安装域控都要找教程,每次都没法一次性搞定.写个笔记吧...主要是给自己看的.写的比较含糊.不清楚的可以直接QQ本人. 1.安装WIN2008R2,192.168.188.10 2.上载SLICET ...

  10. 【洛谷】P1754 球迷购票问题(基础dp)

    题目背景 盛况空前的足球赛即将举行.球赛门票售票处排起了球迷购票长龙. 按售票处规定,每位购票者限购一张门票,且每张票售价为50元.在排成长龙的球迷中有N个人手持面值50元的钱币,另有N个人手持面值1 ...