編輯:關於Android編程
在Android系統中,有兩種播放聲音的方式,一種是通過MediaPlayer,另外一種是通過SoundPool。前者主要用於播放長時間的音樂,而後者用於播放小段小段的音效,像按鍵音這種,其優點是資源占用了小,同時能夠載入多個聲音片段,再根據需要選擇播放。下面分別介紹這兩種方式:
1、MediaPlayer
MediaPlayer有兩種創建方式,方式一:
MediaPlayer mp = new MediaPlayer()通過這種方式創建MediaPlayer對象,必須在創建對象之後使用下面的語句:
mp.setDataSource("filePath"); mp.prepare();然後就是調用start()方法。注意使用這種方法設置播放的音樂的時候需要使用的是路徑,這樣對於一般的應用使用起來就不是很方便,不能直接打包到apk中。
mp = MediaPlayer.create(this, R.raw.music);通過這種方式創建MediaPlayer對象,就不需要setDataSource()和prepare()了,直接start()就好了。
當需要停止播放音樂的時候,使用下面的方式:
if(mp.isPlaying()){ mp.stop(); } mp.reset();需要注意的是,在stop之前一定要確認mp正在播放,因為如果已經停止播放了,再次stop會引發錯誤的,原因就是MediaPlayer有一個嚴格的生命周期,在錯誤的時期調用錯誤的方法,是一定會報錯的。
2、SoundPool
SoundPool在播放音效的時候特別的好用,為什麼呢?因為它可以一次load較多的聲音片段。下面首先介紹其基本的使用方法:
//創建 SoundPool sp = new SoundPool(10, StreamType.MUSIC, 5); //載入 soundPoolMap = new HashMap各個函數中參數的具體意義不是重點,這裡就不做介紹了,各位自己去查一下。我想要說的是,如果各位在主線程中直接這麼做,很可能會報錯(Sample X Not Ready),這是為什麼呢?(); soundPoolMap.put(0, soundPool.load(context, R.raw.sound1, 1)); //播放 soundPool.play(soundPoolMap.get(0), 1, 1, 0, 0, 1);
原來,SoundPool.load()這個函數是立即返回的,也就是說,不管載入好了沒有,這個函數都會返回,但是實際上非常有可能聲音尚未載入結束,那應該怎麼做呢?實際上,系統在load完成之後,會發送廣播,這時候才能播放。又因為這是一個費時的操作,所以最好新建一個線程來實現。下面是我的實現方案:
Handler handler; static SoundPool soundPool; static HashMapsoundPoolMap; String TAG = "wtianok"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() .add(R.id.container, new PlaceholderFragment()).commit(); } soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 5); soundPoolMap = new HashMap (); // 載入soundPool new LoadSoundPoolThread().run(this); handler = new Handler() { public void handleMessage(android.os.Message msg) { if (msg.what == MessageType.SOUND_POOL_READY.ordinal()) { Log.d(TAG, "finish load message received"); //do somethind } } } } private class LoadSoundPoolThread extends Thread { public void run(Context context) { Log.d(TAG, "start to load soundpool"); soundPool.setOnLoadCompleteListener(new MyOnLoadCompleteListener()); soundPool.load(context, R.raw.sound1, 1); soundPool.load(context, R.raw.sound2, 1); soundPool.load(context, R.raw.sound3, 1); soundPool.load(context, R.raw.sound4, 1); soundPool.load(context, R.raw.sound5, 1); soundPool.load(context, R.raw.sound6, 1); soundPool.load(context, R.raw.sound7, 1); } private class MyOnLoadCompleteListener implements OnLoadCompleteListener { int count = 1; @Override public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { //注意這裡的形參 Log.d(TAG, "load " + count + " sound"); soundPoolMap.put(count, sampleId); if (count == 7) { Log.d(TAG, "finish load soundpool"); MainActivity.soundPool = soundPool; sendMsg(MessageType.SOUND_POOL_READY); count = 1; } count++; } } } private void sendMsg(MessageType micTestStartRecord) { Message message = Message.obtain(); message.what = micTestStartRecord.ordinal(); handler.sendMessage(message); }
MainActivity.soundPool = soundPool;如果不加這一句,我在主線程中play的時候,依然會報Sample X Not Ready錯誤,而如果在收到廣播之後調用play是沒有問題的。仔細看,發現在接收廣播的onLoadComplete()函數中,實際上調用的是函數的局部參數soundPool,而不是全局的soundPool,但是從代碼來看,load的時候調用的確實全局的soundPool,那為什麼用全局的soundPool就不能播放呢?我到現在還是沒有想通,但是項目還是要繼續,只好加了上面那一句,將全局的soundPool重新賦值,事實證明,這樣做可以。
本文介紹一個app最常見的特性,就是新功能屬性介紹和啟動屏,一般會怎麼實現呢,這不就打算告訴大家了麼。先說邏輯 先判斷是否第一次啟動app,如果是,則進入功能使用導航(
前言Handler是Android消息機制的上層接口,平時使用起來很方便,我們可以通過它把一個任務切換到Handler所在的線程中去運行。而最常用的就是拿來從子線程切換到
在Android開發中,我們常用的布局方式主要有LinearLayout、RelativeLayout、FrameLayout等,通過這些布局我們可以實現各種各樣的界面。
轉載須注明。 一個博士同學,找到我,想我合伙,幫助他解決移動端產品。他給我描述了他的想法,搜布,用圖像識別的算法去搜索布匹,然後推薦,然後關聯商家。這麼一個