先上代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
><!--定义一个垂直的线性布局 -->
<TextView
android:id="@+id/textView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="没有播放任何声音"
/><!-- 向线性布局中添加一个TextView控件 -->
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="使用MediaPlayer播放声音"
/><!-- 向线性布局中添加一个Button控件 -->
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂停MediaPlayer声音"
/><!-- 向线性布局中添加一个Button控件 -->
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="使用SoundPool播放声音"
/><!-- 向线性布局中添加一个Button控件 -->
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂停SoundPool声音"
/><!-- 向线性布局中添加一个Button控件 -->
</LinearLayout>
public class Main4Activity extends AppCompatActivity implements View.OnClickListener{
Button button1;//四个按钮的引用
Button button2;
Button button3;
Button button4;
TextView textView;//TextView的引用
MediaPlayer mMediaPlayer;
SoundPool soundPool;//声音
HashMap<Integer, Integer> soundPoolMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
textView = (TextView) this.findViewById(R.id.textView);//得到TextView的引用
button1 = (Button) this.findViewById(R.id.button1);//得到button的引用
button2 = (Button) this.findViewById(R.id.button2);
button3 = (Button) this.findViewById(R.id.button3);
button4 = (Button) this.findViewById(R.id.button4);
button1.setOnClickListener(this);//为四个按钮添加监听
button2.setOnClickListener(this);
button3.setOnClickListener(this);
button4.setOnClickListener(this);
initSounds();
}
private void initSounds() {
mMediaPlayer = MediaPlayer.create(this,R.raw.backsound);
soundPool = new SoundPool(4, AudioManager.STREAM_MUSIC,100);
soundPoolMap = new HashMap<>();
soundPoolMap.put(1,soundPool.load(this,R.raw.dingdong,1));
}
public void playSound(int sound,int loop){
//用SoundPoll播放声音的方法
AudioManager mgr = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
float streamVolumeCurrent = mgr.getStreamVolume(AudioManager.STREAM_MUSIC);
float streamVolumeMax = mgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
float volume = streamVolumeCurrent/streamVolumeMax;
soundPool.play(soundPoolMap.get(sound), volume, volume, 1, loop, 1f);//播放声音
}
@Override
public void onClick(View v) {
if (v == button1) {//点击了使用MediaPlayer播放声音按钮
textView.setText("使用MediaPlayer播放声音");
if (!mMediaPlayer.isPlaying()) {
mMediaPlayer.start();//播放声音
}
}
else if (v == button2) {//点击了暂停MediaPlayer声音按钮
textView.setText("暂停了MediaPlayer播放的声音");
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();//暂停声音
}
}
else if (v == button3) {//点击了使用SoundPool播放声音按钮
textView.setText("使用SoundPool播放声音");
this.playSound(1, 0);
}
else if (v == button4) {//点击了暂停SoundPool声音按钮
textView.setText("暂停了SoundPool播放的声音");
soundPool.pause(1);//暂停SoundPool的声音
}
}
}
上面是demo,下面看一下SoundPool的用法
如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:
1) 延时时间较长,且资源占用率高。
2) 不支持多个音频同时播放。
Android中除了MediaPlayer播放音频之外还提供了SoundPool来播放音效,SoundPool使用音效池的概念来管理多个短促的音效,例如它可以开始就加载20个音效,以后在程序中按音效的ID进行播放。
SoundPool主要用于播放一些较短的声音片段,与MediaPlayer相比,SoundPool的优势在于CPU资源占用量低和反应延迟小。另外,SoundPool还支持自行设置声音的品质、音量、 播放比率等参数。
SoundPool提供了一个构造器,该构造器可以指定它总共支持多少个声音(也就是池的大小)、声音的品质等。构造器如下:
SoundPool(int maxStreams, int streamType, int srcQuality):第一个参数指定支持多少个声音;第二个参数指定声音类型:第三个参数指定声音品质。
一旦得到了SoundPool对象之后,接下来就可调用SoundPool的多个重载的load方法来加载声音了。
SoundPool提供了如下4个load方法:
int load(Context context, int resld, int priority):从 resld 所对应的资源加载声音。
int load(FileDescriptor fd, long offset, long length, int priority):加载 fd 所对应的文件的offset开始、长度为length的声音。
int load(AssetFileDescriptor afd, int priority):从afd 所对应的文件中加载声音。
int load(String path, int priority):从path 对应的文件去加载声音。
上面4个方法中都有一个priority参数,该参数目前还没有任何作用,Android建议将该 参数设为1,保持和未来的兼容性。
上面4个方法加载声音之后,都会返回该声音的的ID,以后程序就可以通过该声音的ID 来播放指定声音。
SoundPool提供的播放指定声音的方法:
int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate):该方法的第一个参数指定播放哪个声音;leftVolume、rightVolume指定左、右的音量:priority指定播放声音的优先级,数值越大,优先级越高;loop指定是否循环,0为不循环,-1为循环;rate指定播放的比率,数值可从0.5到2, 1为正常比率。
为了更好地管理SoundPool所加载的每个声音的1D,程序一般会使用一个HashMap对象来管理声音。
归纳起来,使用SoundPool播放声音的步骤如下:
1) 调用SoundPool的构造器创建SoundPool的对象。
2) 调用SoundPool对象的load()方法从指定资源、文件中加载声音。最好使用HashMap< Integer, Integer>来管理所加载的声音。
3) 调用SoundPool的play方法播放声音。
下面的程序示范了如何使用SoundPool来播放音效。
MediaPlayer
静态构造方法
方法名称 | 描述 |
public static MediaPlayer create(Context context, Uri uri, SurfaceHolder holder) | 指定从资源ID对应的资源文件中来装载音乐文件,同时指定了SurfaceHolder对象并返回MediaPlyaer对象 |
public static MediaPlayer create(Context context, int resid) | 指定从资源ID对应的资源文件中来装载音乐文件,并返回MediaPlyaer对象 |
public static MediaPlayer create(Context context, Uri uri) | 指定从Uri对应的资源文件中来装载音乐文件,并返回MediaPlyaer对象 |
常用方法
方法名称 | 描述 |
public void start () | 开始或恢复播放 |
public void stop() | 停止播放 |
public void pause() | 暂停播放 |
public void setDataSource (String path) | 从指定的装载path路径所代表的文件 |
public void setDataSource (FileDescriptor fd, long offset, long length) | 指定装载fd所代表的文件中从offset开始、长度为length的文件内容 |
public void setDataSource (FileDescriptor fd) | 指定装载fd所代表的文件 |
public void setDataSource (Context context, Uri uri) | 指定装载uri所代表的文件 |
public void setDataSource (Context context, Uri uri, Map<String, String> headers) | 指定装载uri所代表的文件 |
public void prepare() | 预期准备,因为setDataSource()方法之后,MediaPlayer并未真正的去装载那些音频文件,需要调用prepare()这个方法去准备音频 |
public void setLooping(boolean looping) | 设置是否循环播放这个音乐文件 |
public void setSurface(Surface surface) | 设置Surface |
public void setVolume(float leftVolume,float rightVolume) | 设置音量 |
public void setDisplay(SurfaceHolder sh) | 设置显示方式 |
public void seekTo(int mses) | 寻求指定的时间位置。 |
public void isLooping() | 判断是否循环播放 |
public void isPlaying() | 判断是否正在播放 |
public void release() | 释放相关该MediaPlayer对象的资源。 |
绑定事件监听器
监听器 | 描述 |
public void setOnCompletionListener (MediaPlayer.OnCompletionListener listener) | 为MediaPlayer的播放完成事件绑定事件监听器 |
public void setOnErrorListener (MediaPlayer.OnErrorListener listener) | 为MediaPlayer的播放错误事件绑定事件监听器 |
public void setOnPreparedListener (MediaPlayer.OnPreparedListener listener) | 当MediaPlayer调用prepare()方法时触发该监听器 |
public void setOnSeekCompleteListener (MediaPlayer.OnSeekCompleteListener listener) | 当MediaPlayer调用seek()方法的时候触发该监听器 |
播放音频
1、播放应用的资源文件(res/raw/)
通过我们上面介绍的几个静态构造函数创建MediaPlayer对象
2、播放应用的原始资源文件(assets)
1) 通过Context.getAssets()方法获得AssetManager对象
2) 通过AssetManager对象的openFd(String name)方法打开指定的原生资源文件夹,返回一个AssetFileDescriptor对象
3) 通过AssetFileDescriptor的getFileDescriptor()得到一个FileDescriptor对象
4) 通过public void setDataSource (FileDescriptor fd, long offset, long length)来创建MediaPlayer对象
5) 调用MediaPlayer.prepare()方法准备音频
6) 调用MediaPlayer的start()、pause()、stop()等方法控制
3、播放外部存储上的音频资源文件(sdcard)
1) 创建MediaPlayer对象,通过MediaPlayer对象的setDataSource(String path)方法装载预定的音频文件
2) 调用MediaPlayer对象的prepare()方法准备音频
3) 调用MediaPlayer的start()、pause()、stop()等方法控制
4、播放网络上的音频文件
1) 根据网络上的地址创建Uri对象
2) 通过public void setDataSource (Context context, Uri uri)设置音频来源装载音频文件
3) 调用MediaPlayer对象的prepare()方法准备音频
4) 调用MediaPlayer的start()、pause()、stop()等方法控制
当然也可以通过我们的另一种静态构造方法直接创建一个MediaPlayer对象