如果应用程序经常播放密集、短促的音效,这时使用 MediaPalyer 就不合适了。MediaPalyer 的缺点如下:
-----> 资源占用量较高,延迟时间较长。
-----> 不支持多个音频同时播放。
Android 提供了 SoundPool 来播放音效,SoundPool 使用音效池的概念管理多个音效,例如它可以开始就加载10个音效,以后在程序中按银熊的 ID 进行播放。
SoundPool 主要用于播放一些较短的声音片段,与 MediaPalyer 相比,SoundPool 的优势在与 CPU 资源占用量低和反应延迟小。另外,SoundPool 还支持自行设置声音的品质、音量、播放比率等参数。提供了 SoundPool 的一个 Builder 内部类来创建 SoundPool (从 Android5.0 开始推荐使用 SoundPool.Builder 来创建 SoundPool 对象)。
获得 SoundPool 对象后,可调用 SoundPool 的多个重载的 load() 方法来加载声音。SoundPool 提供了 4 个 load() 方法:
-----> int load(String path, int priority):从 path 对应的文件中去加载声音。
-----> int load(AssetFileDescriptor afd, int priority):从 afd 所对应的文件中加载声音。
-----> int load(Context context, int resId, int priority):从 resId 所对应的资源加载声音。
-----> int load(FileDescriptor fd, long offset, long length, int priority):加载 fd 所对应的文件中从 offset 开始,长度为 length 的声音。
上面的方法中都有一个 priority 参数,Android 建议将该参数设为 1。
加载声音后,SoundPool 提供的播放指定声音的方法如下:
final 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 为正常比率。
一般会使用一个 HashMap<Integer, Integer> 对象来管理声音。
代码示例如下:
package com.crazy.media;
import android.app.Activity;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.SoundPool;
import android.media.SoundPool.Builder;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import java.util.HashMap;
public class MainActivity extends Activity implements OnClickListener
{
Button bomb, shot, arrow;
// 定义一个SoundPool
SoundPool soundPool;
HashMap<Integer, Integer> soundMap = new HashMap<>();
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bomb = (Button) findViewById(R.id.bomb);
shot = (Button) findViewById(R.id.shot);
arrow = (Button) findViewById(R.id.arrow);
AudioAttributes attr = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME) // 设置音效使用场景
// 设置音效的类型
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build();
soundPool = new SoundPool.Builder()
.setAudioAttributes(attr) // 设置音效池的属性
.setMaxStreams(10) // 设置最多可容纳10个音频流,
.build(); // (1)
// load方法加载指定音频文件,并返回所加载的音频ID
// 此处使用HashMap来管理这些音频流
soundMap.put(1, soundPool.load(this, R.raw.bomb, 1)); // (2)
soundMap.put(2, soundPool.load(this, R.raw.shot, 1));
soundMap.put(3, soundPool.load(this, R.raw.arrow, 1));
bomb.setOnClickListener(this);
shot.setOnClickListener(this);
arrow.setOnClickListener(this);
}
// 重写OnClickListener监听器接口的方法
@Override
public void onClick(View source)
{
// 判断哪个按钮被单击
switch (source.getId())
{
case R.id.bomb:
soundPool.play(soundMap.get(1), 1, 1, 0, 0, 1); // (3)
break;
case R.id.shot:
soundPool.play(soundMap.get(2), 1, 1, 0, 0, 1);
break;
case R.id.arrow:
soundPool.play(soundMap.get(3), 1, 1, 0, 0, 1);
break;
}
}
}
代码中(1)用于创建 SoundPool 对象;(2)使用 SoundPool 加载多个不同的声音;(3)根据声音 ID 来播放指定
声音。
注:虽然 SoundPool 比 MediaPlayer 的效率好,但也不是绝对不存在延迟问题,尤其是那些手机性能不太好的手机,
延迟可能更加的严重。
VideoView 组件位于 android.widget 包下,其作用于 ImageView 类似,VideoPlayer 用于播放视频。
使用 VideoView 播放视频的步骤如下:
(1)、在布局界面中定义 VideoView 组件,或者在程序中创建 VideoView 组件;
(2)、调用 VideoView 的如下两个方法来加载指定视频;
-----> setVideoPath(String path):加载 path 文件所代表的视频。
-----> setVideoURI(Uri uri):加载 uri 所对应的视频。
(3)、调用 VideoView 的 start()、stop()、pause() 方法来控制视频播放。
MediaController 可以与 VideoView 结合使用,MediaController 的作用是提供一个友好的图形控制界面,通过该控制界面来控制视频的播放。
示例如下:
activity_main.xml:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 定义VideoView播放视频 -->
<VideoView
android:id="@+id/video"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
MainActivity.java :
package com.crazy.media;
import android.app.Activity;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.MediaController;
import android.widget.VideoView;
import java.io.File;
public class MainActivity extends Activity
{
VideoView videoView;
MediaController mController;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
setContentView(R.layout.activity_main);
// 获取界面上VideoView组件
videoView = (VideoView) findViewById(R.id.video);
// 创建MediaController对象
mController = new MediaController(this);
File video = new File("/mnt/sdcard/movie.mp4");
if(video.exists())
{
videoView.setVideoPath(video.getAbsolutePath()); // (1)
// 设置videoView与mController建立关联
videoView.setMediaController(mController); // (2)
// 设置mController与videoView建立关联
mController.setMediaPlayer(videoView); // (3)
// 让VideoView获取焦点
videoView.requestFocus();
}
}
}
相应的权限:
<!-- 授予该程序读取外部存储器的权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>