前言

  在Android中播放音频文件经常会用到MediaPlayer,但是MediaPlayer存在一些不足的地方,如:资源占用量较高、加载延迟时间较长、不支持多个音频同时播放等。这些缺点决定了MediaPlayer在某些需要密集使用不同音频的情况不会理想,例如游戏开发。在游戏开发中,我们经常需要播放一些游戏的音效,这些音效的都需要是短促、密集、延迟小的,在这种场景下,需要使用到SoundPool来替代MediaPlayer播放这些音效,本篇博客就主要讲解SoundPool的使用以及需要注意的地方,最后将以一个示例演示SoundPool的使用。

  本篇博客的主要内容:

  1. SoundPool
  2. SoundPool的简单示例
  3. SoundPool的注意事项

SoundPool

  SoundPool(声音池),所处于"android.media.SoundPool"包下,主要用于播放一些较短的声音片段,支持从程序的资源或文件系统加载。与MediaPlayer相比,SoundPool的优势在于CPU的资源占用量低、反应延迟小,并且可以加载多个音频到SoundPool中,通过资源ID来管理。另外SoundPool还支持执行设置声音的品质、音量、播放比率等参数。

  SoundPool提供一个构造函数,以下是它的完整签名:

    SoundPool(int maxStreams,int streamType,int srcQuality)

  通过上面的构造函数即可完成SoundPool的初始化,第一个参数为音频池最多支持装载多少个音频,就是音频池的大小;第二个参数指定声音的类型,在AudioManager类中以常量的形式定义,一般指定为AudioManager.STREAM_MUSIC即可;第三个参数为音频的质量,默认为0,这个参数为预留参数,现在没有实际意义,为扩展预留字段,一般传0即可。

  对于一个音频池,涉及到音频的加载、播放、暂停、继续、释放资源等操作,SoundPool也为我们提供了相应的方法,其底层也是用C++编写的native方法。以下介绍一些常用的SoundPool方法:

  • int load(Context context,int resId,int priority):从一个文件夹raw下装载一段音频资源,返回值为音频资源在SoundPool的ID。
  • int load(String path,int priority):从一个资源文件的路径装载一段音频资源,返回值为音频资源在SoundPool的ID。
  • final int play(int soundID,float leftVolume,float rightVolume,int priority,int loop,float rate):根据资源ID,播放一段音频资源。
  • final void pause(int streamID):根据装载资源ID,暂停音频资源的播放。
  • final void resume(int streamID):根据装载资源ID,继续播放暂停的音频资源。
  • final void stop(int streamID):根据装载资源ID,停止音频资源的播放。
  • final boolean unload(int soundID) :从音频池中卸载音频资源ID为soundID的资源。
  • final void release():释放音频池资源。

  上面方法无疑Load()和play()是最重要的,Load()具有多种重载方法,从参数名就可以看出是什么意思。这里讲解一下play()方法,soundID参数为资源ID;leftVolume和rightVolume个参数为左右声道的音量,从大到小取0.0f~1.0f之间的值;priority为音频质量,暂时没有实际意义,传0即可;loop为循环次数,0为播放一次,-1为无线循环,其他正数+1为播放次数,如传递3,循环播放4次;rate为播放速率,从大到小取0.0f~2.0f,1.0f为正常速率播放。

  在使用load()装载音频的时候需要注意,load()方法是一个异步的方法,也就是说,在播放音频的时候,很可能此段音频还没有装载到音频池中,这里可以借助SoundPool的一个装载完成的监听事件SoundPool.setOnLoadCompleteListener来保证装载完成在播放声音。SoundPool.setOnLoadCompleteListener()需要实现一个SoundPool.OnLoadCompleteListener接口,其中需要实现onLoadComplete()方法,一下是onLoadComplete()方法的完整签名:

    onLoadComplete(SoundPool soundPool, int sampleId, int status)

  • soundPool:当前触发事件的声音池。
  • sampleId:当前装载完成的音频资源在音频池中的ID。
  • status:状态码,展示没有意义,为预留参数,会传递0。

使用SoundPool示例

  上面已经介绍了SoundPool的使用所涉及到的内容,下面通过一个简单的示例来演示一下SoundPool的使用,播放的音频资源都是我从其他app中拷贝出来的,没有实际意义。示例中的注释写的比较全,这里不再累述了。

 package cn.bgxt.soundpooldemo;

 import java.util.HashMap;
import java.util.Map; import android.media.AudioManager;
import android.media.SoundPool;
import android.media.SoundPool.OnLoadCompleteListener;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast; public class MainActivity extends Activity {
private Button btn_newqqmsg, btn_newweibontf, btn_newweibotoast;
private SoundPool pool;
private Map<String, Integer> poolMap; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_newqqmsg = (Button) findViewById(R.id.btn_newqqmsg);
btn_newweibontf = (Button) findViewById(R.id.btn_newweibontf);
btn_newweibotoast = (Button) findViewById(R.id.btn_newweibotoast); poolMap = new HashMap<String, Integer>();
// 实例化SoundPool,大小为3
pool = new SoundPool(3, AudioManager.STREAM_MUSIC, 0);
// 装载音频进音频池,并且把ID记录在Map中
poolMap.put("newqqmsg", pool.load(this, R.raw.qqmsg, 1));
poolMap.put("newweibontf", pool.load(this, R.raw.notificationsound, 1));
poolMap.put("newweibotoast", pool.load(this, R.raw.newblogtoast, 1)); pool.setOnLoadCompleteListener(new OnLoadCompleteListener() { @Override
public void onLoadComplete(SoundPool soundPool, int sampleId,
int status) {
// 每次装载完成均会回调
Log.i("main", "音频池资源id为:" + sampleId + "的资源装载完成");
// 当前装载完成ID为map的最大值,即为最后一次装载完成
if (sampleId == poolMap.size()) {
Toast.makeText(MainActivity.this, "加载声音池完成!",
Toast.LENGTH_SHORT).show();
btn_newqqmsg.setOnClickListener(click);
btn_newweibontf.setOnClickListener(click);
btn_newweibotoast.setOnClickListener(click);
// 进入应用播放四次声音
pool.play(poolMap.get("newweibotoast"), 1.0f, 1.0f, 0, 3,
1.0f);
}
}
});
} private View.OnClickListener click = new OnClickListener() { @Override
public void onClick(View v) { switch (v.getId()) {
case R.id.btn_newqqmsg:
if (pool != null) {
pool.play(poolMap.get("newqqmsg"), 1.0f, 1.0f, 0, 0, 1.0f);
}
break;
case R.id.btn_newweibontf:
if (pool != null) {
pool.play(poolMap.get("newweibontf"), 1.0f, 1.0f, 0, 0,
1.0f);
}
break;
case R.id.btn_newweibotoast:
if (pool != null) {
pool.play(poolMap.get("newweibotoast"), 1.0f, 1.0f, 0, 0,
1.0f);
}
break;
default:
break;
}
}
}; @Override
protected void onDestroy() {
// 销毁的时候释放SoundPool资源
if (pool != null) {
pool.release();
pool = null;
}
super.onDestroy();
}
}

  效果展示:

SoundPool使用的注意事项

  因为SoundPool的一些设计上的BUG,从固件版本1.0开始就有些没有修复的,以后应该会慢慢修复。这里简单提一下:

  1. 虽然SoundPool可以装载多个音频资源,但是最大只能申请1MB的内存空间,这就意味着只能用使用它播放一些很短的声音片段,而不是用它来播放歌曲或者做游戏背景音乐。
  2. SoundPool提供的pause()、resume()、stop()最好不要轻易使用,因为它有时候会使程序莫名其妙的终止,如果使用,最好做大量的测试。而且有时候也不会立即终止播放声音,而是会等缓冲区的音频数据播放完才会停止。
  3. 虽然SoundPool比MediaPlayer的效率好,但也不是绝对不存在延迟的问题,尤其在那些性能不太好的手机中,SoundPool的延迟问题会更严重,但是现在一般的手机配置,那一点的延迟还是可以接受的。

  源码下载

总结

  本篇博客介绍了SoundPool的使用,虽然SoundPool还有一些不足的地方,当时对于应用中一些简短的特效音,如按键音、短消息音,或者一些游戏中密集的声音,如射击的枪声,爆破的声音等。都是可以使用SoundPool的,效率会比使用MediaPlayer要高的多。

Android--SoundPool的更多相关文章

  1. Android SoundPool.play方法的音量与系统音量的关系

    Android中播放音频,除了使用MediaPlayer,还可以使用SoundPool.SoundPool使用音效池的概念来管理多个短促的音效,对于需要短促的提示音的场景特别合适. 通常调用Sound ...

  2. android SoundPool播放音效

    MediaPlayer的缺点: 资源占用量高,延时时间较长 不支持多个音效同一时候播放 SoundPool主要用于播放一些较短的声音片段,CPU资源占用率低和反应延时小,还支持自行色设置声音的品质,音 ...

  3. Android SoundPool 的使用以及原理分析

    好吧,我们今天来聊聊SoundPool这东西. 据说这个东西是冰激凌(Android4.0)里才引入的一个新东西.按照官方的意思大多数情况下是给游戏开发用的,比如一个游戏10关,它能在游戏开始前一次加 ...

  4. Android soundpool初探

    内容:本编播客主要讲解一下“即时音效”: 特点:快,短. 在播放这类时间短但是要求反应迅速的的音效,就不能够用不能够使用播放时间较长的音乐播放技术了,而应该采取soundpool技术来播放. soun ...

  5. android soundpool 參数说明

    SoundPool 类的构造函数例如以下: SoundPool(int maxStreams, int streamType, int srcQuality) 作用:实例化一个SoundPool 实例 ...

  6. [android] soundpool简介

    主要的应用场景是游戏开发的时候,声音都比较短,比较密集,使用这个api来实现 池:实现了一个链表,旧的资源不会被释放掉,而是存起来,等用的时候,重新使用 不会创建过多的对象 在res资源目录里面创建一 ...

  7. Android 云之声离线语音合成

    离线语音解析 public class SpeechUtilOffline implements TTSPlayerListener { public static final String appK ...

  8. Android 使用SoundPool播放音效

    在Android开发中我们经常使用MediaPlayer来播放音频文件,但是MediaPlayer存在一些不足,例如:资源占用量较高.延迟时间较长.不支持多个音频同时播放等.这些缺点决定了MediaP ...

  9. Android音频播放之SoundPool

    SoundPool 一.基本概念 在Android应用程序的开发过程中,经常需要播放多媒体文件,也许最先想到的会是MediaPlayer类了,该类提供了播放.暂停.停止及重复播放等功能性方法(该类位于 ...

  10. Android中的音频播放(MediaPlayer和SoundPool)

    Android中音频和视频的播放我们最先想到的就是MediaPlayer类了,该类提供了播放.暂停.停止.和重复播放等方法.该类位于android.media包下,详见API文档.其实除了这个类还有一 ...

随机推荐

  1. 2016-3-1 安装Hexo过程中遇到的问题

      查找问题地址: http://hexo.io/docs/troubleshooting.html   1.通过npm安装hexo运行命令:sudo npm install -g hexo 出现这个 ...

  2. 使用HttpClient发送文件流到服务器端

    适用场景:网络绝对路径的URL文件或图片,不存储到本地,转换成stream,直接使用HTTPClient传送到SpringBoot的服务端,将文件存储下来,并返回一个文件地址.目前分层架构的系统越来越 ...

  3. JS精度问题(0.1+0.2 = 0.3吗?)

    一.引出问题 0.1+0.2 = 0.3吗?在JS中是这样的吗?我们写个测试代码不就知道了吗? 结果出人意料,并不像我们所想象的那样.那么这到底是为什么呢? 二.原因分析 JS浮点数存储机制: 三.解 ...

  4. System.getProperty(String key)方法获取常用系统信息

    其中key可以为以下选项: 1.java.version Java 运行时环境版本 2.java.vendor Java 运行时环境供应商 3.java.vendor.url Java 供应商的 UR ...

  5. Do Now 一个让你静心学习的APP——团队博客

    Do Now 一个让你静心学习的APP 来自油条只要半根团队的智慧凝聚的产物! 团队博客总目录: 团队作业第一周 团队作业第二周 Do Now -- 团队冲刺博客一 Do-Now-团队Scrum 冲刺 ...

  6. [JZOJ3588]【中山市选2014】J语言(表达式解析+栈)

    Description J语言作为一门编程语言,诞生于20世纪90年代.............. 好学的小H今天又学到了一种新东西——J语言.显然,J语言的背景已经被小H忘得一干二净了,但是小H仍然 ...

  7. docker之使用System.Drawing生成图片缺少Gdiplus.dll错误

    1.在docker 上找到并运行需要System.Drawing的镜像 然后退出执行另一语句 docker run -it container01 进入镜像以方便安装gdiplus docker ex ...

  8. emoji 表情: MySQL如何支持 emoji 表情

    https://www.cnblogs.com/jentary/p/6655471.html 修改数据库字符集: ALTER DATABASE database_name CHARACTER SET ...

  9. linux 做了raid后,硬盘坏了更换问题

    系统做完raid1后发现 raid盘坏了,硬盘都是热插拔的,更换后,需要简单配置一下才能自动进行镜像拷贝. 在pd mgmt 页面,选择新加入的硬盘,按F2,选择 make global HS选项 选 ...

  10. git教程——安装配置

    Git(读音为/gɪt/.)是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到非常大的项目版本管理. Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个 ...