編輯:關於Android編程
Android SDK為我們提供了SoundPool 用於播放游戲音效,還提供了MediaPlayer為我們提供游戲音樂的播放。SoundPool(android.media.SoundPool),顧名思義是聲音池的意思,主要用於播放一些較短的聲音片段,支持從程序的資源或文件系統加載。
SoundPool技術
在游戲開發中我們經常需要播放一些游戲音效(比如:子彈爆炸,物體撞擊等),這些音效的共同特點是短促、密集、延遲程度小。在這樣的場景下我們可以使用SoundPool。
SoundPool特性:
1. SoundPool最大只能申請1M的內存空間,這就意味著我們只能使用一些很短的聲音片段,而不是用它來播放歌曲或者游戲背景音樂。
2. SoundPool提供了pause和stop方法,但這些方法建議最好不要輕易使用。
3. 音頻格式建議使用OGG格式。
SoundPool使用方法:
1. 創建一個SoundPool
public SoundPool(int maxStream, int streamType, int srcQuality)
maxStream —— 同時播放的流的最大數量
streamType —— 流的類型,一般為STREAM_MUSIC(具體在AudioManager類中列出)
srcQuality —— 采樣率轉化質量,當前無效果,使用0作為默認值
eg.
SoundPool soundPool = new SoundPool(3, AudioManager.STREAM_MUSIC, 0);
創建了一個最多支持3個流同時播放的,類型標記為音樂的SoundPool。
2 soundpool的加載:
int load(Context context, int resId, int priority) //從APK資源載入
int load(FileDescriptor fd, long offset, long length, int priority) //從FileDescriptor對象載入
int load(AssetFileDescriptor afd, int priority) //從Asset對象載入
int load(String path, int priority) //從完整文件路徑名載入
最後一個參數為優先級。
3 播放
play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate) ,
其中leftVolume和rightVolume表示左右音量 取值范圍(range = 0.0 to 1.0)
priority表示優先級
loop表示循環次數
rate表示速率,如
//速率最低0.5最高為2,1代表正常速度
sp.play(soundId, 1, 1, 0, 0, 1);
關於音頻流:
在Android系統中有多種音頻流,通過Activity中的函數 setVolumeControlStream(int streamType)可以設置該Activity中音量控制鍵控制的音頻流,一般在onCreate函數中設置。
Android中有如下幾種音頻流(streamType是需要調整音量的類型):
AudioManager.STREAM_MUSIC /音樂回放即媒體音量/
AudioManager.STREAM_RING /鈴聲/
AudioManager.STREAM_ALARM /警報/
AudioManager.STREAM_NOTIFICATION /窗口頂部狀態欄通知聲/
AudioManager.STREAM_SYSTEM /系統/
AudioManager.STREAM_VOICECALL /通話 /
AudioManager.STREAM_DTMF /雙音多頻/
仔細分析了SoundPool 的API後,毫無疑問我們應該讓事情簡單些。
編寫AndroidSoundPool類簡化SoundPool的使用
[java] package com.gaofeng.game;
import java.io.IOException;
import java.util.*;
import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.media.SoundPool;
public class AndroidSoundPool {
AssetManager assets;
SoundPool soundPool;
HashMap<String,Integer> soundMap=new HashMap<String,Integer>();
public AndroidSoundPool(Activity activity) {
activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
this.assets = activity.getAssets();
this.soundPool = new SoundPool(20, AudioManager.STREAM_MUSIC, 0);
}
/** 從asset中加載聲音文件
* @param filename 聲音文件名
* @param identifer 聲音標識名,在播放聲音時調用
*/
public void load(String filename,String identifer) {
try {
AssetFileDescriptor assetDescriptor = assets.openFd(filename);
int soundId = soundPool.load(assetDescriptor, 0);
soundMap.put(identifer, soundId);
} catch (IOException e) {
throw new RuntimeException("Couldn't load sound '" + filename + "'");
}
}
/**根據聲音標識名播放聲音
* @param identifer 聲音標識名,在加載聲音load方法中被設置的
* @param volume 播放音量
*/
public void play(String identifer,float volume) {
soundPool.play(soundMap.get(identifer), volume, volume, 0, 0, 1);
}
/**根據聲音標識名播放聲音
* @param identifer 聲音標識名,在加載聲音load方法中被設置的
*/
public void play(String identifer) {
soundPool.play(soundMap.get(identifer), 1, 1, 0, 0, 1);
}
/**卸載聲音
* @param identifer 聲音標識名,在加載聲音load方法中被設置的
* @return
*/
public boolean unload(String identifer) {
return soundPool.unload(soundMap.get(identifer));
}
}
package com.gaofeng.game;
import java.io.IOException;
import java.util.*;
import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.media.SoundPool;
public class AndroidSoundPool {
AssetManager assets;
SoundPool soundPool;
HashMap<String,Integer> soundMap=new HashMap<String,Integer>();
public AndroidSoundPool(Activity activity) {
activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
this.assets = activity.getAssets();
this.soundPool = new SoundPool(20, AudioManager.STREAM_MUSIC, 0);
}
/** 從asset中加載聲音文件
* @param filename 聲音文件名
* @param identifer 聲音標識名,在播放聲音時調用
*/
public void load(String filename,String identifer) {
try {
AssetFileDescriptor assetDescriptor = assets.openFd(filename);
int soundId = soundPool.load(assetDescriptor, 0);
soundMap.put(identifer, soundId);
} catch (IOException e) {
throw new RuntimeException("Couldn't load sound '" + filename + "'");
}
}
/**根據聲音標識名播放聲音
* @param identifer 聲音標識名,在加載聲音load方法中被設置的
* @param volume 播放音量
*/
public void play(String identifer,float volume) {
soundPool.play(soundMap.get(identifer), volume, volume, 0, 0, 1);
}
/**根據聲音標識名播放聲音
* @param identifer 聲音標識名,在加載聲音load方法中被設置的
*/
public void play(String identifer) {
soundPool.play(soundMap.get(identifer), 1, 1, 0, 0, 1);
}
/**卸載聲音
* @param identifer 聲音標識名,在加載聲音load方法中被設置的
* @return
*/
public boolean unload(String identifer) {
return soundPool.unload(soundMap.get(identifer));
}
}
AndroidSoundPool 通過內置一個 HashMap<String,Integer> 實現了音效和聲音標識的映射,使用的時候需要首先調用load方法加載音效文件,指定聲音標識,然後再通過play方法根據音效對應的聲音標識進行播放。
下面是AndroidSoundPool 的使用方法:
[java] import com.gaofeng.game.AndroidSoundPool;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.TextView;
public class AudioTest extends Activity implements OnTouchListener {
AndroidSoundPool andoridsoundpool;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textView = new TextView(this);
textView.setOnTouchListener(this);
setContentView(textView);
//創建AndroidSoundPool
andoridsoundpool = new AndroidSoundPool(this);
//加載聲音文件explode.ogg,指定該聲音標識為:sExplode
andoridsoundpool.load("explode.ogg", "sExplode");
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
//根據聲音標識sExplode播放聲音文件
andoridsoundpool.play("sExplode");
}
return true;
}
}
import com.gaofeng.game.AndroidSoundPool;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.TextView;
public class AudioTest extends Activity implements OnTouchListener {
AndroidSoundPool andoridsoundpool;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textView = new TextView(this);
textView.setOnTouchListener(this);
setContentView(textView);
//創建AndroidSoundPool
andoridsoundpool = new AndroidSoundPool(this);
//加載聲音文件explode.ogg,指定該聲音標識為:sExplode
andoridsoundpool.load("explode.ogg", "sExplode");
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
//根據聲音標識sExplode播放聲音文件
andoridsoundpool.play("sExplode");
}
return true;
}
}
MediaPlayer技術
MediaPlayer使用簡單,適合做游戲的背景音樂,但資源占用量較高、延遲時間較長、不支持多個音頻同時播放等。
下面介紹MediaPlayer的相關技術:
1.獲取MediaPlayer實例
MediaPlayer.create(Context context,int resId);
//參數一:上下文對象,參數二:音樂資源ID
2.MediaPlayer常用的函數
prepare();//為播放音樂文件做准備工作
start();//播放音樂
pause();//暫停音樂播放
stop();//停止音樂播放
pause()和stop()主要的區別在於:暫停播放後可以調用start()繼續播放,停止音樂播放後,需要調用prepare()再調用start()進行播放音樂。
3.MediaPlayer其它常用函數
setLooping(boolean looping);//設置音樂是否循環播放,true為循環播放
seekTo(int msec);//將音樂播放跳轉到某一時間點,以毫秒為單位
getDuration();//獲取播放的音樂文件總時間長度
getCurrentPosition();//獲取當前播放音樂時間點
仔細分析了MediaPlayer的API後,毫無疑問我們應該讓事情簡單些。
編寫AndroidMusicPool簡化音樂播放
[java] import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.MediaPlayer;
public class AndroidMusicPool {
AssetManager assets;
HashMap<String,AndroidMusic> musicMap=new HashMap<String,AndroidMusic>();
public AndroidMusicPool(Activity activity) {
this.assets = activity.getAssets();
}
/*
* 從asset中加載音樂文件
* filename:加載的文件名
* identifer:聲音標志名,音樂標識名,播音樂時調用
* */
public void load(String filename,String identifer) {
AssetFileDescriptor assetDescriptor=null;
try {
assetDescriptor = assets.openFd(filename);
} catch (IOException e) {
e.printStackTrace();
}
AndroidMusic music = new AndroidMusic(assetDescriptor);
musicMap.put(identifer, music);
}
/**根據音樂標識符播放音樂
* @param identifer 音樂標識符
* @param volume 音量大小
*/
public void play(String identifer,float volume) {
if(!musicMap.containsKey(identifer))return;
musicMap.get(identifer).setVolume(volume);
musicMap.get(identifer).play();
}
/*根據音樂標識符播放音樂
* */
public void play(String identifer) {
if(!musicMap.containsKey(identifer))return;
musicMap.get(identifer).play();
}
//根據音樂標識符停止音樂
public void stop(String identifer) {
if(!musicMap.containsKey(identifer))return;
musicMap.get(identifer).stop();
}
//根據音樂標識符設定循環播放
public void setLooping(String identifer,boolean isLooping) {
if(!musicMap.containsKey(identifer))return;
musicMap.get(identifer).setLooping(isLooping);
}
//根據音樂標識符暫停音樂
public void pause(String identifer) {
if(!musicMap.containsKey(identifer))return;
musicMap.get(identifer).pause();
}
//根據音樂標識符注銷音樂
public void dispose(String identifer) {
if(!musicMap.containsKey(identifer))return;
musicMap.get(identifer).dispose();
musicMap.remove(identifer);
}
//根據音樂標識符獲取音樂
public AndroidMusic getMusic(String identifer) throws Exception
{
if(!musicMap.containsKey(identifer))
throw new Exception("no music for identifer found") ;
return musicMap.get(identifer);
}
/*清除所有的音樂*/
public void clear()
{
Iterator<Entry<String, AndroidMusic>> iter
= musicMap.entrySet().iterator();
while (iter.hasNext()) {
musicMap.get(iter.next().getKey()).dispose();
}
musicMap.clear();
}
}
//該類是對MediaPlayer的輕度封裝
class AndroidMusic {
MediaPlayer mediaPlayer;
boolean isPrepared = false;
public AndroidMusic(AssetFileDescriptor assetDescriptor) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(assetDescriptor.getFileDescriptor(),
assetDescriptor.getStartOffset(),
assetDescriptor.getLength());
mediaPlayer.prepare();
isPrepared = true;
} catch (Exception e) {
throw new RuntimeException("Couldn't load music");
}
}
public void dispose() {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.release();
}
public boolean isLooping() {
return mediaPlayer.isLooping();
}
public boolean isPlaying() {
return mediaPlayer.isPlaying();
}
public boolean isStopped() {
return !isPrepared;
}
public void pause() {
if (mediaPlayer.isPlaying())
mediaPlayer.pause();
}
public void play() {
if (mediaPlayer.isPlaying())
return;
try {
synchronized (this) {
if (!isPrepared)
mediaPlayer.prepare();
mediaPlayer.start();
}
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setLooping(boolean isLooping) {
mediaPlayer.setLooping(isLooping);
}
public void setVolume(float volume) {
mediaPlayer.setVolume(volume, volume);
}
public void stop() {
mediaPlayer.stop();
synchronized (this) {
isPrepared = false;
}
}
}
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.MediaPlayer;
public class AndroidMusicPool {
AssetManager assets;
HashMap<String,AndroidMusic> musicMap=new HashMap<String,AndroidMusic>();
public AndroidMusicPool(Activity activity) {
this.assets = activity.getAssets();
}
/*
* 從asset中加載音樂文件
* filename:加載的文件名
* identifer:聲音標志名,音樂標識名,播音樂時調用
* */
public void load(String filename,String identifer) {
AssetFileDescriptor assetDescriptor=null;
try {
assetDescriptor = assets.openFd(filename);
} catch (IOException e) {
e.printStackTrace();
}
AndroidMusic music = new AndroidMusic(assetDescriptor);
musicMap.put(identifer, music);
}
/**根據音樂標識符播放音樂
* @param identifer 音樂標識符
* @param volume 音量大小
*/
public void play(String identifer,float volume) {
if(!musicMap.containsKey(identifer))return;
musicMap.get(identifer).setVolume(volume);
musicMap.get(identifer).play();
}
/*根據音樂標識符播放音樂
* */
public void play(String identifer) {
if(!musicMap.containsKey(identifer))return;
musicMap.get(identifer).play();
}
//根據音樂標識符停止音樂
public void stop(String identifer) {
if(!musicMap.containsKey(identifer))return;
musicMap.get(identifer).stop();
}
//根據音樂標識符設定循環播放
public void setLooping(String identifer,boolean isLooping) {
if(!musicMap.containsKey(identifer))return;
musicMap.get(identifer).setLooping(isLooping);
}
//根據音樂標識符暫停音樂
public void pause(String identifer) {
if(!musicMap.containsKey(identifer))return;
musicMap.get(identifer).pause();
}
//根據音樂標識符注銷音樂
public void dispose(String identifer) {
if(!musicMap.containsKey(identifer))return;
musicMap.get(identifer).dispose();
musicMap.remove(identifer);
}
//根據音樂標識符獲取音樂
public AndroidMusic getMusic(String identifer) throws Exception
{
if(!musicMap.containsKey(identifer))
throw new Exception("no music for identifer found") ;
return musicMap.get(identifer);
}
/*清除所有的音樂*/
public void clear()
{
Iterator<Entry<String, AndroidMusic>> iter
= musicMap.entrySet().iterator();
while (iter.hasNext()) {
musicMap.get(iter.next().getKey()).dispose();
}
musicMap.clear();
}
}
//該類是對MediaPlayer的輕度封裝
class AndroidMusic {
MediaPlayer mediaPlayer;
boolean isPrepared = false;
public AndroidMusic(AssetFileDescriptor assetDescriptor) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(assetDescriptor.getFileDescriptor(),
assetDescriptor.getStartOffset(),
assetDescriptor.getLength());
mediaPlayer.prepare();
isPrepared = true;
} catch (Exception e) {
throw new RuntimeException("Couldn't load music");
}
}
public void dispose() {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.release();
}
public boolean isLooping() {
return mediaPlayer.isLooping();
}
public boolean isPlaying() {
return mediaPlayer.isPlaying();
}
public boolean isStopped() {
return !isPrepared;
}
public void pause() {
if (mediaPlayer.isPlaying())
mediaPlayer.pause();
}
public void play() {
if (mediaPlayer.isPlaying())
return;
try {
synchronized (this) {
if (!isPrepared)
mediaPlayer.prepare();
mediaPlayer.start();
}
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setLooping(boolean isLooping) {
mediaPlayer.setLooping(isLooping);
}
public void setVolume(float volume) {
mediaPlayer.setVolume(volume, volume);
}
public void stop() {
mediaPlayer.stop();
synchronized (this) {
isPrepared = false;
}
}
}以上代碼中包含兩個類AndroidMusic 和 AndroidMusicPool ,AndroidMusic 其實是對MediaPlayer的輕度封裝,在AndroidMusicPool中會調用AndroidMusic 進行音樂播放,而AndroidMusicPool可以看作音樂容器, 通過內置一個 HashMap 實現了音樂和音樂標識的映射,使用的時候需要首先調用load方法加載音樂文件,指定音樂標識,然後再通過play方法根據音樂標識進行播放。
如果上述代碼讓你感到疑惑,也不必太糾結了,因為重要的是知道如何去使用,請看下面的實例代碼:
使用AndroidMusicPool 播放音樂
以下代碼演示:當我們輕觸屏幕時,音樂就會響起。
[java] public class AudioTest extends Activity implements OnTouchListener {
AndroidMusicPool musicpool;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textView = new TextView(this);
textView.setOnTouchListener(this);
setContentView(textView);
musicpool = new AndroidMusicPool(this);
//從assets中加載音樂文件music.mp3,並設定其音樂標識為:mMusic
musicpool.load("music.mp3", "mMusic");
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
//根據音樂標識mMusic播放音樂
musicpool.play("mMusic");
}
return true;
}
}
public class AudioTest extends Activity implements OnTouchListener {
AndroidMusicPool musicpool;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textView = new TextView(this);
textView.setOnTouchListener(this);
setContentView(textView);
musicpool = new AndroidMusicPool(this);
//從assets中加載音樂文件music.mp3,並設定其音樂標識為:mMusic
musicpool.load("music.mp3", "mMusic");
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
//根據音樂標識mMusic播放音樂
musicpool.play("mMusic");
}
return true;
}
}
AndroidMusicPool通過短短兩行代碼就實現了音樂的加載和播放,簡單吧,但是請記住,在調用播放方法play之前,務必先調用load方法加載音樂文件,並指定音樂標識。
前言:有一天在寫代碼的時候,我想達到如下效果: AndroidManifest中的windowSoftInputMode屬性,我將其設置為adjustResize,正常來
在安全衛生上,經常看到有圓形的進度條在轉動,效果非常好看,於是就嘗試去實現一下,具體實現過程不多說了,直接上效果圖,先炫耀下。效果圖:分析:比較常見於掃描結果、進度條等場
1、AlertDialog對話框 AlertDialog.Builder builder=new Builder(HomeActivity.this); buil
本文實例講述了Android編程之頁面切換測試。分享給大家供大家參考。具體分析如下:一、軟件平台:win7 + eclipse + sdk二、設計思路:兩個頁面:mian