手把手叫你制作一个精美的在线音乐播放器

article/2025/10/31 7:54:29

最近项目中要增加一些特殊的功能,实现音乐的在线播放。虽说网上源码一大把,demo一大堆,但是能用的其实寥寥无几抓狂,看来关键时刻还是自己动手,丰衣足食啊。话不多说,直接看效果图吧:


看是不是很美观。

该功能主要是实现:从后台请求一个音乐地址,进而实现在线播放,且能够支持暂停,快进,以及播放进度条,播放时间等。


代码不是很多,主要是用MediaPlayer重要工具类

这里控制着音乐的播放,暂停,开始播放等播放状态。

 public void play() {new Thread(new Runnable() {@Overridepublic void run() {if (player.mediaPlayer.isPlaying() || getPlayStatus() == PlayStatus.PLAYING) {player.pause();setPlayStatus(PlayStatus.PAUSE);} else if(getPlayStatus() == PlayStatus.NOPLAY || getPlayStatus() == PlayStatus.FINISH){if(getPlayStatus() == PlayStatus.FINISH){player.mediaPlayer.reset();//重置MediaPlayer到初始化状态player.mediaPlayer.seekTo(0);//须将播放时间设置到0;这样才能在下次播放是重新开始,否则会继续上次播放}player.playUrl(URLMUSIC);setPlayStatus(PlayStatus.PLAYING);}else if(getPlayStatus() == PlayStatus.PAUSE){player.start();//继续播放setPlayStatus(PlayStatus.PLAYING);}}}).start();}

这里要注意的是:

 player.mediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {@Overridepublic void onBufferingUpdate(MediaPlayer mp, int percent) {Long totleLong = new Long((long) player.mediaPlayer.getDuration());Long currentLong = new Long((long) player.mediaPlayer.getCurrentPosition());String totleTime = formatter.format(mp.getDuration());String currentTime = formatter.format((mp.getCurrentPosition()));LogUtil.e(TAG,"totle:  " +totleTime+"当前:  " + currentTime);if(mp.isPlaying()){//减少误差,避免得到getDuration()的时间出问题---->在这里花费了好多的时间mySeekProgressListener.onMySeekProgressData(totleTime,currentTime,0);if(totleTime.equals(currentTime)){//用这样的方式判断完成,减少时间的误差LogUtil.e(TAG,"我进来啦!!!");setPlayStatus(PlayStatus.FINISH);player.mediaPlayer.pause();// player.mediaPlayer.release();}}}});

这里的  setOnBufferingUpdateListener是用于音乐或者视频在线缓冲的更新监听器

 public class SeekBarChangeEvent implements SeekBar.OnSeekBarChangeListener {int progress;@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {LogUtil.e(TAG,"totle:  " +player.mediaPlayer.getDuration());this.progress  = progress * player.mediaPlayer.getDuration() / seekBar.getMax();}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {player.mediaPlayer.seekTo(progress);if(getPlayStatus() == PlayStatus.FINISH) {play();}}}

这里是坚挺拖动条的拖动状态,用于显示在线音乐的进度,当然是SeekBar能进行拖动。

以下是全部代码:

public class MainActivity extends Activity implements View.OnClickListener{private final int MUSIC_FINISH = 1000;@Bind(R.id.iv_bg_music)ImageView iv_bg_music;@Bind(R.id.titlebar_back_music)ImageView titlebar_back_music;@Bind(R.id.titlebar_title_music)TextView titlebar_title_music;@Bind(R.id.ib_paly_music)//播放音乐ImageButton ib_paly_music;@Bind(R.id.ll_to_play)//播放音乐LinearLayout ll_to_play;@Bind(R.id.tv_time_progress)//正在播放的时间TextView tv_time_progress;@Bind(R.id.tv_time_totle)//播放总时间TextView tv_time_totle;@Bind(R.id.sb_music_progress)//播放拖动条SeekBar sb_music_progress;private MusicPlay mausicPlay;private SimpleDateFormat formatter;private Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what){case MUSIC_FINISH:tv_time_progress.setText("0:00");//播放完毕后,重新设置没有播放的状态sb_music_progress.setProgress(0);ib_paly_music.setBackgroundResource(R.drawable.iv_paly);break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButterKnife.bind(this);initListener();initView();}private void initView() {formatter = new SimpleDateFormat("mm:ss");formatter.setTimeZone(TimeZone.getTimeZone("GMT+00:00"));mausicPlay = MusicPlay.getInstance(this).setMySeekListener(sb_music_progress).setMySeekProgressListener(new MusicPlay.MySeekProgressListener() {@Overridepublic void onMySeekProgressData(String totleTime, String currentTime,int finishStatus) {if(finishStatus == 100){//播放完毕LogUtil.e("yuyahao","mian 时间 放放完啦!!! ");}else{tv_time_totle.setText(totleTime);if(totleTime.equals(currentTime)){//用时间字符串进行比较,防止出现两次的时间结束状态handler.postDelayed(new Runnable() {@Overridepublic void run() {Message msg = handler.obtainMessage();msg.what = MUSIC_FINISH;handler.sendMessage(msg);}}, 800);}else{tv_time_totle.setText(totleTime);tv_time_progress.setText(currentTime);}}}});ib_paly_music.setTag(R.drawable.iv_stop_paly);ib_paly_music.setBackgroundResource(R.drawable.iv_paly);}private void initListener() {ib_paly_music.setOnClickListener(this);titlebar_back_music.setOnClickListener(this);ll_to_play.setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.ll_to_play:case R.id.ib_paly_music://博faNG或者是暂停Integer tag = (Integer) ib_paly_music.getTag();if(mausicPlay.isPlayIng()){//正在播放,去暂停播放ib_paly_music.setBackgroundResource(R.drawable.iv_paly);}else{//去进行播放ib_paly_music.setBackgroundResource(R.drawable.iv_stop_paly);}mausicPlay.play();break;case R.id.titlebar_back_music:onBackPressed();break;}}@Overrideprotected void onDestroy() {super.onDestroy();if(mausicPlay != null){mausicPlay.onDestroy();}}@Overridepublic void onBackPressed() {if(mausicPlay.isPlayIng()){}else{super.onBackPressed();}}
}

工具类:

/*** Created by fei on 2016/11/12.* 音乐在线播放  工具类*/
public class MusicPlay {private static final String TAG = "yyh";private static Player player;private static MusicPlay musicPlay;private String URLMUSIC = "http://abv.cn/music/红豆.mp3";private Context context;private static PlayStatus isPlaystatic  = PlayStatus.NOPLAY;//播放状态:默认0不播放,  1:开始博播放 ,2是暂停播放 ,3:是播放完毕private static SimpleDateFormat formatter;//private  SeekBar sb_music_progress;//当前播放的拖动条public enum  PlayStatus{NOPLAY(0),//默认0不播放PLAYING(1),//,1:开始博播放PAUSE(2),//,2是暂停播放FINISH(3);//3:是播放完毕private int status;PlayStatus(int status) {this.status = status;}public int getStatus() {return status;}public void setStatus(int status) {this.status = status;}}public MusicPlay(Context context) {this.context = context;}public static void  setPlayStatus(PlayStatus isPlaystatic){MusicPlay.isPlaystatic = isPlaystatic;}public PlayStatus getPlayStatus(){return this.isPlaystatic;}public static MusicPlay getInstance(Context context) {if (musicPlay == null) {musicPlay = new MusicPlay(context);formatter = new SimpleDateFormat("mm:ss");formatter.setTimeZone(TimeZone.getTimeZone("GMT+00:00"));}return musicPlay;}public  MusicPlay setMySeekListener(SeekBar sb_music_progress){sb_music_progress.setOnSeekBarChangeListener(new SeekBarChangeEvent());player  = new Player(sb_music_progress);initSetMediaPlaylistener();return musicPlay;}public  MusicPlay setMySeekProgressListener(MySeekProgressListener mySeekProgressListener){this.mySeekProgressListener = mySeekProgressListener;return musicPlay;}private static MySeekProgressListener mySeekProgressListener;public interface  MySeekProgressListener{void onMySeekProgressData(String totleTime, String currentTime, int finishStatus);}/*** 是否在进行播放* @return*/public boolean isPlayIng(){return player.mediaPlayer.isPlaying();}/*** 释放资源*/public void release(){player.mediaPlayer.release();}public void play() {new Thread(new Runnable() {@Overridepublic void run() {if (player.mediaPlayer.isPlaying() || getPlayStatus() == PlayStatus.PLAYING) {player.pause();setPlayStatus(PlayStatus.PAUSE);} else if(getPlayStatus() == PlayStatus.NOPLAY || getPlayStatus() == PlayStatus.FINISH){if(getPlayStatus() == PlayStatus.FINISH){player.mediaPlayer.reset();//重置MediaPlayer到初始化状态player.mediaPlayer.seekTo(0);//须将播放时间设置到0;这样才能在下次播放是重新开始,否则会继续上次播放}player.playUrl(URLMUSIC);setPlayStatus(PlayStatus.PLAYING);}else if(getPlayStatus() == PlayStatus.PAUSE){player.start();//继续播放setPlayStatus(PlayStatus.PLAYING);}}}).start();}/*** 开始播放*/public void startPlay() {new Thread(new Runnable() {@Overridepublic void run() {}}).start();}/*** 停止播放*/public void stopPlay() {}/*** 继续播放*/public void continuePlay() {}private static void initSetMediaPlaylistener(){/*player.mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {Long totleLong = new Long((long) player.mediaPlayer.getDuration());mySeekProgressListener.onMySeekProgressData(totleLong,0L,100);LogUtil.i(TAG, mp.getDuration()+"我已完成啦!!!!");}});*/player.mediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {@Overridepublic void onBufferingUpdate(MediaPlayer mp, int percent) {Long totleLong = new Long((long) player.mediaPlayer.getDuration());Long currentLong = new Long((long) player.mediaPlayer.getCurrentPosition());String totleTime = formatter.format(mp.getDuration());String currentTime = formatter.format((mp.getCurrentPosition()));LogUtil.e(TAG,"totle:  " +totleTime+"当前:  " + currentTime);if(mp.isPlaying()){//减少误差,避免得到getDuration()的时间出问题---->在这里花费了好多的时间mySeekProgressListener.onMySeekProgressData(totleTime,currentTime,0);if(totleTime.equals(currentTime)){//用这样的方式判断完成,减少时间的误差LogUtil.e(TAG,"我进来啦!!!");setPlayStatus(PlayStatus.FINISH);player.mediaPlayer.pause();// player.mediaPlayer.release();}}}});}public class SeekBarChangeEvent implements SeekBar.OnSeekBarChangeListener {int progress;@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {LogUtil.e(TAG,"totle:  " +player.mediaPlayer.getDuration());this.progress  = progress * player.mediaPlayer.getDuration() / seekBar.getMax();}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {player.mediaPlayer.seekTo(progress);if(getPlayStatus() == PlayStatus.FINISH) {play();}}}/*** 销毁时*/public void onDestroy() {if (player != null && player.mediaPlayer.isPlaying()) {player.stop();
//            player.mediaPlayer.pause();player = null;}setPlayStatus(PlayStatus.NOPLAY);}public void palyByMobileSevice(){Intent intent = new Intent();Uri uri = Uri.parse(URLMUSIC);intent.setDataAndType(uri, "audio/mp3");//  intent.setDataAndType(uri, "audio/*");这里可以改成audio/mp3intent.setAction(Intent.ACTION_VIEW);context.startActivity(intent);}
}
最后一个:

public class Player implements OnBufferingUpdateListener, OnCompletionListener,OnPreparedListener{public MediaPlayer mediaPlayer;private SeekBar seekBar;private Timer mTimer = new Timer();public Player(SeekBar seekBar) {super();this.seekBar = seekBar;try {mediaPlayer = new MediaPlayer();mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.setOnBufferingUpdateListener(this);mediaPlayer.setOnPreparedListener(this);} catch (Exception e) {e.printStackTrace();}mTimer.schedule(timerTask, 0, 1000);}TimerTask timerTask = new TimerTask() {@Overridepublic void run() {if (mediaPlayer == null)return;if (mediaPlayer.isPlaying() && seekBar.isPressed() == false) {handler.sendEmptyMessage(0);}}};Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {int position = mediaPlayer.getCurrentPosition();int duration = mediaPlayer.getDuration();if (duration >= 0) {long pos = seekBar.getMax() * position / duration;seekBar.setProgress((int) pos);}};};public void play() {mediaPlayer.start();}/*** * @param url*/public void playUrl(String url) {try {mediaPlayer.reset();mediaPlayer.setDataSource(url);mediaPlayer.prepare();mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);// 通过异步的方式装载媒体资源/*mediaPlayer.prepareAsync();mediaPlayer.setOnPreparedListener(new OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mp) {// 装载完毕回调mediaPlayer.start();}});*/} catch (IllegalArgumentException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (IllegalStateException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}public void pause() {mediaPlayer.pause();}public void start() {mediaPlayer.start();}public void stop() {if (mediaPlayer != null) {mediaPlayer.stop();mediaPlayer.release();mediaPlayer = null;}}@Overridepublic void onPrepared(MediaPlayer mp) {mp.start();Log.e("mediaPlayer", "onPrepared");}@Overridepublic void onCompletion(MediaPlayer mp) {Log.e("mediaPlayer", "onCompletion");}@Overridepublic void onBufferingUpdate(MediaPlayer mp, int percent) {seekBar.setSecondaryProgress(percent);int currentProgress = seekBar.getMax()* mediaPlayer.getCurrentPosition() / mediaPlayer.getDuration();Log.e(currentProgress + "% play", percent + " buffer");}}

但是到了最后竟然忘记写权限了:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

否则就会播放不出来。报一些其他类型的错误。

好了,最后贴上项目地址:http://download.csdn.net/detail/androidstarjack/9690396

另外你觉得此篇文章对您有所帮助 请关注终端研发部,QQ交流群 :232203809




http://chatgpt.dhexx.cn/article/4ufFOx88.shtml

相关文章

微信小程序中将图片与音乐制作成MV

最近一直在开发一个类似于小年糕的微信小程序&#xff0c;在开发制作MV功能时 &#xff0c;花费了一些心思&#xff0c;其间主要遇到了以下一些问题点&#xff1a; 1. 上传图片的动画效果如何像播放视频一样实现播放与暂停&#xff1f; 2. 用户上传的图片数量不确定&#xf…

FL Studio中文版21最新免费音乐编曲软件制作工具

FL Studio较为适合专业的音乐制作者&#xff0c;操作难度较大&#xff0c;学习门槛也较高&#xff1b;Studio One则主打一站式的音乐制作&#xff0c;从编曲到录音到后期的专辑制作都可以在其中实现&#xff0c;同时操作难度不大&#xff0c;对初学者和业余爱好者都较为友好。 …

mv

mv 移动文件或改名 mv 命令&#xff08;move 的缩写&#xff09;&#xff0c;既可以在不同的目录之间移动文件或目录&#xff0c;也可以对文件和目录进行重命名。 该命令的基本格式如下&#xff1a; [rootlocalhost ~]# mv 【选项】 源文件 目标文件“mv” 默认执行命令(mv -…

怎样做音乐相册怎样制作?手把手教你制作

大家平时出门游玩的时候&#xff0c;会拍摄一些好看的照片吗&#xff1f;那你们会将这些照片分享在社交平台上吗&#xff1f;普通的照片分享&#xff0c;有时会显得比较枯燥单调&#xff0c;其实我们可以将这些照片制作成音乐相册&#xff0c;这样就可以丰富照片的内容&#xf…

Audacity(电脑音频剪辑软件)官方中文版V3.0.2 | 完全免费的音乐制作软件audacity下载

Audacity 是一款专业易于使用且完全免费的音乐制作软件&#xff0c;高度可定制的界面能实时显示预览&#xff0c;具备多轨音频剪辑和音频录制功能&#xff0c;提供了数十种可修改或自己创建的插件以及无限的撤消和重做能力&#xff0c;能将磁带和唱片转换成数字唱片或 CD&#…

手把手教你批量制作MV连播视频

一、点击下载CR MVMixer解压到D盘 找到图标双击打开CR MVMixer 本软件授权注册码可以登陆酷软街获取 右下角点击注册&#xff0c;填入注册码激活。 软件操作页面&#xff0c;左侧是加载音乐MP3跟LRC歌词的 右侧可以添加视频素材&#xff0c;设置封面。 二、加载素材&#xf…

MV制作器UI版来噜

一、项目介绍 MV制作器UI版来噜 在之前的制作MV的项目中&#xff0c;我们使用代码来调用文心大模型API&#xff0c;批量的获取图片&#xff0c;然后我们需要使用专业德视频剪辑工具譬如pr或剪映等完成后续的步骤&#xff0c;但并不是所有人都会使用剪辑软件… 那有没有什么可…

轻音——基于Swing与JavaFx的音乐播放器

简介 轻音是一款我个人开发的支持本地和在线音乐的播放器&#xff0c;我制作这款软件的初衷也是为了消除不同平台之间版权的差异&#xff0c;让听歌不再“跨平台化”&#xff0c;实现听歌自由使用的技术&#xff1a;100% Java 编程语言&#xff0c;98% Swing 开发GUI&#xff…

LaTeX会议论文添加版权信息

1. 在导言区增加 \usepackage{fancyhdr} \renewcommand{\headrulewidth}{0pt} \renewcommand{\footrulewidth}{0pt} 2. maketitle后增加 \thispagestyle{fancy} \fancyhead{} \lhead{} \lfoot{\copyright~2014 IEEE} \cfoot{} \rfoot{}&#xff0c; 效果如下

CCF论文会议 IEEE 如何查询某个会议期刊的所有文章

1. 下载CCF英文列表 CCF英文会议期刊 列表目录 下载 2. 找到要查询的会议&#xff0c;点击后面的网址 3. 就可以看到该会议期刊列年的整理好的记录&#xff0c;随便点击一个进入 4. 可以看到该年收录的所有文章 5. 可以点击这里查看文章详情 微程序学堂

会议论文扩展摘要写作指南 conference extended abstract

简单的讲就是一个迷你版的论文&#xff0c;除了篇幅非常短只有2-4页之外&#xff0c;论文该有的部分都要有&#xff08;e.g. Introduction, Methods, Discussion …&#xff09;。扩展摘要可能需要包含一个abstract&#xff0c;也可能直接从introduction开始&#xff0c;视不同…

计算机发顶级会议论文难,发会议论文不如发期刊?被反驳的无言以对……

顶级会议和顶级期刊哪个牛?是不是发会议不如发期刊呢? 本期关键词:SCI期刊,顶级会议,计算机 有网友在小木虫开帖称自己投稿中了机器人和自动化领域top会议——IROS2012,引发网友关于“投会议论文还是投期刊”的大讨论。 “真心恭喜楼主呀!不过国内不太认可会议呀,有这水…

撰写全英文EI会议论文值得注意的要点!

首先&#xff0c;EI会议论文有用吗&#xff1f;当然是有用的&#xff0c;EI是国际上三大检索系统之一&#xff0c;所以EI论文肯定是有用的&#xff0c;是受认可的&#xff0c;但EI检索的不单单是学术期刊&#xff0c;还有学术会议&#xff0c;期刊论文和会议论文是不同的&#…

ISTP会议论文检索

目录 1. ISTP会议论文的概念 2. ISTP会议论文的特点 3. ISTP会议论文检索 4. ISTP会议论文检索基本检索&#xff0c;检索步骤 1. ISTP会议论文的概念 ISTP会议论文是指在学术会议上宣读和交流的论文、报告及其他有关资料&#xff0c;包括会议前参加会议者预先提交的论文文…

参考文献是会议论文应该什么格式?

“既然你诚心诚意的发问了&#xff0c;那我就大发慈悲的告诉你!”(请自行带入火箭队三人组语气&#xff0c;谢谢&#xff01;) 注意啦&#xff01;参考文献会议论文的必须要素在此&#xff01; [序号]作者名题名[C]//&#xff08;出版地&#xff09;出版者出版年&#xff08;…

会议论文和期刊论文在写作上有什么区别?有什么侧重点?

作为一名科研工作者&#xff0c;无论你是初入圈内的“小萌新”还是久经沙场的“老将”&#xff0c;写论文都是我们的必经之路&#xff0c;而要想论文投中&#xff0c;就需要我们的积极努力啦&#xff01;其中&#xff0c;杂志社以及很多大型学术会议的征稿就是很好的一个途径哦…

科普文章:会议论文VS期刊论文,两者有何区别?学界的认可度两者一致吗?

文章目录 一、会议论文和期刊论文的概念1.1 会议论文1.2 期刊论文1.3 总结 二、不同之处2.1 内容的不同2.2 审稿周期的不同2.3 认可度的区别 三、投稿的一些建议四、自己的一点小想法 计算机深度学习方向研一学生一枚&#xff0c;论文才有想法&#xff0c;下一步打算开始写了&a…

Petri网学习(五):Petri网子类的性质分析

一、标识S-图 S-图定义&#xff1a; 定义&#xff1a;网N(P,T;F)是S-图或状态机当且仅当&#xff1a;&#xff0c;而带有标识的S-图称为标识S-图。将S-图中的变迁撤掉可以简化为有向图SG(P,E) 我对S-图的理解&#xff1a;所有的变迁都是单进单出。 S-图的性质&#xff1a; 1、…

软件工程----有穷状态机和Petri网

有穷状态机 概念 有穷状态机的作用是描述对象在它的生命周期内所经历状态序列&#xff0c;以及如何响应来自外界的事件。有穷状态机首先包含一个有限状态的集合&#xff0c;还包含了从一个状态到另外一个状态的转换。 有穷自动机看上去就像是一个有向图&#xff0c;其中状态…

很久以前某位大仙对petri网的总结

2006年03月14日 计算模型的统一分析 计算模型的统一分析 人类所有的计算模型都包括如下四个要素&#xff1a; 1&#xff09;输入集合或者输入变量&#xff08;I&#xff09;&#xff1b; 2&#xff09;输出集合或者输出变量&#xff08;O&#xff09;&#x…