Android 音乐(音效)播放方式总结
一、音效的分类
音效按照作用的不同,可以将音效分为即时音效和背景音乐。两种音效在Android中的实现技术是不同的。
主要的实现方式为:SoundPool、MediaPlayer。
区别在于,MediaPlayer会在播放音频的时候,会占用大量的系统资源,并且播放的时候,还需要缓冲,有较大的时延。但是SoundPool的机制是将声音资源加载到内存中,然后在需要播放的地方进行播放,几乎没有时延,但是也正是因为这样的机制,限制了加载的文件的大小,不然会出现加载失败或者内存占用过大的情况,原则上SoundPool播放的音效的长度不应该超过7S。
所有如果需要实时播放短时间音效的话,可以使用SoundPool,如果需要播放背景音乐的话,建议使用MediaPlayer。
二、即时音效的播放—SoundPool
相关API文档地址:https://developer.android.com/reference/android/media/SoundPool.html
具体实现代码为:
public class SampleActivity extends Activity {
SoundPool sp; // 声明SoundPool的引用
HashMap<Integer, Integer> hm; // 声明一个HashMap来存放声音文件
int currStreamId;// 当前正播放的streamId
@Override
// 重写onCreate方法
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); // 设置layout
initSoundPool(); // 初始化声音池的方法
Button b1 = (Button) this.findViewById(R.id.Button01); // 获取播放按钮
b1.setOnClickListener // 为播放按钮添加监听器
(new OnClickListener() {
@Override
public void onClick(View v) {
playSound(1, 0); // 播放1号声音资源,且播放一次
// 提示播放即时音效
Toast.makeText(getBaseContext(), "播放即时音效", Toast.LENGTH_SHORT)
.show();
}
});
Button b2 = (Button) this.findViewById(R.id.Button02); // 获取停止按钮
b2.setOnClickListener // 为停止按钮添加监听器
(new OnClickListener() {
@Override
public void onClick(View v) {
sp.stop(currStreamId); // 停止正在播放的某个声音
// 提示停止播放
Toast.makeText(getBaseContext(), "停止播放即时音效", Toast.LENGTH_SHORT)
.show();
}
});
}
// 初始化声音池的方法
public void initSoundPool() {
sp = new SoundPool(4, AudioManager.STREAM_MUSIC, 0); // 创建SoundPool对象
hm = new HashMap<Integer, Integer>(); // 创建HashMap对象
hm.put(1, sp.load(this, R.raw.musictest, 1)); // 加载声音文件musictest并且设置为1号声音放入hm中
}
// 播放声音的方法
public void playSound(int sound, int loop) { // 获取AudioManager引用
AudioManager am = (AudioManager) this
.getSystemService(Context.AUDIO_SERVICE);
// 获取当前音量
float streamVolumeCurrent = am
.getStreamVolume(AudioManager.STREAM_MUSIC);
// 获取系统最大音量
float streamVolumeMax = am
.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
// 计算得到播放音量
float volume = streamVolumeCurrent / streamVolumeMax;
// 调用SoundPool的play方法来播放声音文件
currStreamId = sp.play(hm.get(sound), volume, volume, 1, loop, 1.0f);
}
}
三、背景音效的播放—MediaPlayer
因为SoundPool只适合播放不大于7秒的音效文件,限制较大。背景音乐一般用MediaPlayer来播放。想要很好的用MediaPlayer进行音/视频的播放,首先需要熟悉MediaPlayer的生命周期。这样不仅仅有利于开发人员开发出更加合理的代码,而且可以达到充分利用系统资源的目的。
MediaPlayer的生命周期
MediaPlayer的生命周期包括10种状态,每种状态下可以调用相应的方法来实现音/视频文件的管理或播放。其各个状态及状态间的关系可以用一个简单的流程图来表示,如图所示:
Idle 状态
使用new方法创建一个MediaPlayer对象或者调用了其reset方法时,改MediaPlayer对象处于Idle 状态。
但是通过两种方式进入的idle状态还是有些区别的,主要体现为:如果这个状态下调用了getDuration等方法,若通过reset进入idle状态的话会出发onErrorListener.onError,并且MediaPlayer会进入Error状态。如果是新创建的MediaPlayer对象,则不会触发onError,也不会进入Error状态
End 状态
通过release方法可以进入End状态,只要MediaPlayer对象不再被使用了,就应当尽快将其通过release方法释放掉,以释放其占用的软、硬件资源,这其中有些资源是互斥的(相当于临界资源)。如果MediaPlayer进入了End状态,则不会再进入其他的任何状态了。
Initialized 状态
这个状态比较简单,MediaPlayer调 用 setDataSource方法就进入了 Initialized状态,表示此时要播放的文件已经设置好了。
Prepared 状态
初始化完成之后还需要通过调用prepare或 prepareAsync方法进行准备,这两个方法一个是同 步的,一个是异步的。只有进入了 Prepared状态,才表明MediaPlayer到目前为止都工作正常,可以进行音乐文件的播放。
Preparing 状态
这个状态比较容易理解,主要是与prepareAsync异步准备方法配合,如果异步准备完成,会触发OnPreparedListener.onPrepared,进而进入Prepared状态。
Started 状态
MediaPlayer准备完成后,通过调用start方法,将进入Started状态。所谓Started状态 ,也就是播放中状态,开发中可以使用isPlaying方法测试MediaPlayer是否处于Started状态。 如果播放完毕,而又设置了循环播放,则 MediaPlayer仍然会处于Started状态。类似的,如果在该状态下MediaPlayer调用了 seekTo或 者 start方法均可以让MediaPlayer停 留 在 Started状态。
Pause 状态
Started状态下调用pause方法可以暂停播放,从而进入到Pause状态。MediaPlayer暂停后再次调用start方法则可以继续进行播放,并转到Started状态。暂停状态可以调用seekTo方法,这是不会改变状态的。
Stop状态
Started或Paused状态下均可以调用stop方法停止播放并进入Stop状态,而处于Stop状态的MediaPlayer想要重新播放,需要通过调用prepareAsync或prepare方法返回到先前的Prepared状态重新开始才可以。
Play backCompleted 状态
文件正常播放完毕,而又没有设置循环播放的话就进入该状态,并会触发OnCompletionListener 接口中的onCompletion方法。此时可以调用start方法重新从头播放文件,也可以调用stop方法停 止播放,或者调用seekTo方法来重新定位播放位置。
Error状态
由于某种原因 MediaPlayer出现了错误,则会触发OnErrorListener.onError回调方法,此时MediaPlayer即进入Error状态。及时捕捉并妥善处理这些错误是很重要的,这可以帮助应用程序及 时释放相关的软、硬件资源,也可以改善用户体验。如 果 MediaPlayer进入了 Error状态,可以通过调用reset方法来恢复,使得 MediaPlayer重新返 回 到 Idle状态。
总结
从上述对生命周期的总结介绍可以看出,某些情况发生的时候,MediaPlayer会回调特定监听接口中的事件处理方法。如果在开发中希望使用回调,则需要先向MediaPlayer注册实现了指定监听接口的监听器。
引申
从上述也可以看到,Ijkplayer和这个在方法名定义上,非常类似,目前看,生命周期这块的控制基本上也是和MediaPlayer一样的。或许这也就是为什么,现在播放器大家用Ijkplayer这么多的原因了。
四、音量控制—AudioManager
AudioManager类在Android系统中主要用来进行音/视频播放时的音量控制,使用时的基本步骤如下所列。
- 首先可以调用Activity对象的getSystemService(Context.AUDIO_SERVICE)方法获取AudioManager对象。
- 然后再调用AudioManager类中的相关方法进行音量控制。
Android 音乐(音效)播放方式总结的更多相关文章
- Android点赞音效播放
/** * 音效播放 */ private SoundPool mPool; /** * 音效id */ private int voiceID; voiceID = initSoundPool(); ...
- cocos2d安卓android长音效播放不完全
是因为安卓限制了音效的内存,一般把mp3的比特率压缩一下.就可以搞定了.
- iOS开发系列--音频播放(音效和音乐)播放本地的
音频 在iOS中音频播放从形式上可以分为音效播放和音乐播放.前者主要指的是一些短音频播放,通常作为 点缀音频,对于这类音频不需要进行进度.循环等控制.后者指的是一些较长的音频,通常是主音频,对于这些音 ...
- Android音乐播放器的开发实例
本文将引导大家做一个音乐播放器,在做这个Android开发实例的过程中,能够帮助大家进一步熟悉和掌握学过的ListView和其他一些组件.为了有更好的学习效果,其中很多功能我们手动实现,例如音乐播放的 ...
- iOS: 音效和音乐的播放,封装的工具类
在iOS中音频播放从形式上可以分为音效播放和音乐播放.前者主要指的是一些短音频播放,通常作为点缀音频,对于这类音频不需要进行进度.循环等控制.后者指的是一些较长的音频,通常是主音频,对于这些音频的播放 ...
- Android音乐播放器源码(歌词.均衡器.收藏.qq5.0菜单.通知)
一款Android音乐播放器源码,基本功能都实现了 qq5.0菜单(歌词.均衡器.收藏.qq5.0菜单.通知) 只有向右滑动出现,菜单键和指定按钮都还没有添加. 源码下载:http://code.66 ...
- iOS开发--音乐文件播放工具类的封装(包含了音效的封装)
一.头文件 #import <Foundation/Foundation.h> #import <AVFoundation/AVFoundation.h> @interface ...
- 一款非常简单的android音乐播放器源码分享给大家
一款非常简单的android音乐播放器源码分享给大家,该应用虽然很小,大家常用的播放器功能基本实现了,可能有点还不够完善,大家也可以自己完善一下,源码在源码天堂那里已经有了,大家可以到那里下载学习吧. ...
- Android命令行播放MP3音乐
/*************************************************************************** * Android命令行播放MP3音乐 * 说 ...
随机推荐
- JS event loop
一.为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. Java ...
- SQL Server与MySQL在“存在则更新,不存在则插入”并发处理上的一些差异。
“存在则更新,不存在则插入的逻辑”并发情况下的处理 在sqlserver中: 在sqlserver中,是通过可序列化隔离级别+排它锁的方式来锁定一个范围来实现的当前锁定一个不存在的记录的时候,sqls ...
- week06 12 我们准备数据 前端调用rpc 前后端联调一下
用postman发送请求 出现一个问题 我在return结果前 要将数据转换成字典 所以我们用json.dumps()后再json.load()回来 这样就避免了这个问题 因为数据结构的数据 比如li ...
- 使用LESS对CSS进行预处理
LESS 做为 CSS 的一种形式的扩展,它并没有阉割 CSS 的功能,而是在现有的 CSS 语法上,添加了很多额外的功能,所以学习 LESS 是一件轻而易举的事情. 变量 请注意 LESS 中的变量 ...
- mysql数据库导入与导出
导出 导出数据和表结构: mysqldump -u用户名 -p 数据库名 > 数据库名.sql mysqldump -uroot -p dbname > dbname .sql ...
- 【Spring】浅谈spring为什么推荐使用构造器注入
一.前言 Spring框架对Java开发的重要性不言而喻,其核心特性就是IOC(Inversion of Control, 控制反转)和AOP,平时使用最多的就是其中的IOC,我们通过将组件交由S ...
- python积累二:中文乱码解决方法
根据网上提供的解决方法:添加#coding=utf-8或# -*- coding: utf-8 -*- #coding=utf-8 print "还不行?" 执行结果:还是乱码!: ...
- vue-router 动态添加 路由
动态添加路由可以用了做权限管理.登录后服务器端返回权限菜单,前端动态添加路由 然后在设置菜单 1.vue-router 有方法router.addRoutes(routes) 动态添加更多的路由规则 ...
- Zookeeper 集群配置及启动
准备工作 1. 集群机器 192.168.8.2 192.168.8.6 192.168.8.11 2. 包 zookeeper-3.4.10.tar.gz 集群配置 1. 解压路径 192.168. ...
- 探索未知种族之osg类生物--渲染遍历之GraphicsContext::runOperations
osg::GraphicsContext::runOperations().我们先来看一下这个函数的执行过程. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...