當(dāng)前位置:首頁 > 嵌入式 > 嵌入式軟件
[導(dǎo)讀] 處理音頻焦點盡管某個時刻只有一個activity可以運行,Android卻是一個多任務(wù)環(huán)境.這對使用音頻的應(yīng)用帶來了特殊的挑戰(zhàn),因為只有一個音頻輸出而可能多個媒體都想用它.在An

 處理音頻焦點

盡管某個時刻只有一個activity可以運行,Android卻是一個多任務(wù)環(huán)境.這對使用音頻的應(yīng)用帶來了特殊的挑戰(zhàn),因為只有一個音頻輸出而可能多個媒體都想用它.在Android2.2之前,沒有內(nèi)建的機(jī)制來處理這個問題,所以可能在某些情況下導(dǎo)致壞的用戶體驗.例如,當(dāng)一個用戶正在聽音樂而另一個應(yīng)用需要通知用戶一些重要的事情時,用戶可能由于音樂聲音大而不能聽的通知.從Android2.2開始,平臺為應(yīng)用提供了一個協(xié)商它們?nèi)绾问褂迷O(shè)備音頻輸出的途徑,這個機(jī)制叫做音頻焦點.

當(dāng)你的應(yīng)用需要輸出像樂音和通知之類的音頻時,你應(yīng)該總是請求音頻焦點.一旦應(yīng)用具有了焦點,它就可以自由的使用音頻輸出.但它總是應(yīng)該監(jiān)聽焦點的變化.如果被通知丟失焦點,它應(yīng)該立即殺死聲音或降低到靜音水平(有一個標(biāo)志表明應(yīng)選擇哪一個)并且僅當(dāng)重新獲得焦點后才恢復(fù)大聲播放.

將來的音頻焦點是合作的.所以,應(yīng)用被希望(并被強(qiáng)列鼓勵)遵守音頻焦點的方針,但是卻不是被系統(tǒng)強(qiáng)制的.如果一個應(yīng)用在丟失音頻焦點后依然想大聲播放音樂,系統(tǒng)不會去阻止它.然而用戶卻體驗很壞并且很想把這鳥應(yīng)用卸載.

要請求音頻焦點,你必須從AudioManager調(diào)用requestAudioFocus(),如下所示:

[java]

AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,

AudioManager.AUDIOFOCUS_GAIN);

if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {

// 不能獲得音頻焦點

}

AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,

AudioManager.AUDIOFOCUS_GAIN);

if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {

// 不能獲得音頻焦點

}

requestAudioFocus()的第一個參數(shù)是一個AudioManager.OnAudioFocusChangeListener,它的onAudioFocusChange()方法在音頻焦點發(fā)改變時被調(diào)用.因此,你也應(yīng)該在你的service和activity上實現(xiàn)此接口.例如:

[java]

class MyService extends Service

implements AudioManager.OnAudioFocusChangeListener {

// ....

public void onAudioFocusChange(int focusChange) {

// Do something based on focus change...

}

}

class MyService extends Service

implements AudioManager.OnAudioFocusChangeListener {

// ....

public void onAudioFocusChange(int focusChange) {

// Do something based on focus change...

}

}

參數(shù)focusChange告訴你音頻焦點如何發(fā)生了變化,它可以是以上幾種值(它們都是定義在AudioManager中的常量):

AUDIOFOCUS_GAIN:你已獲得了音頻焦點.

AUDIOFOCUS_LOSS:你已經(jīng)丟失了音頻焦點比較長的時間了.你必須停止所有的音頻播放.因為預(yù)料到你可能很長時間也不能再獲音頻焦點,所以這里是清理你的資源的好地方.比如,你必須釋放MediaPlayer.

AUDIOFOCUS_LOSS_TRANSIENT:你臨時性的丟掉了音頻焦點,很快就會重新獲得.你必須停止所有的音頻播放,但是可以保留你的資源,因為你可能很快就能重新獲得焦點.

AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:你臨時性的丟掉了音頻焦點,但是你被允許繼續(xù)以低音量播放,而不是完全停止.

下面是一個例子:

[java]

public void onAudioFocusChange(int focusChange) {

switch (focusChange) {

case AudioManager.AUDIOFOCUS_GAIN:

// resume playback

if (mMediaPlayer == null) initMediaPlayer();

else if (!mMediaPlayer.isPlaying()) mMediaPlayer.start();

mMediaPlayer.setVolume(1.0f, 1.0f);

break;

case AudioManager.AUDIOFOCUS_LOSS:

// Lost focus for an unbounded amount of time: stop playback and release media player

if (mMediaPlayer.isPlaying()) mMediaPlayer.stop();

mMediaPlayer.release();

mMediaPlayer = null;

break;

case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:

// Lost focus for a short time, but we have to stop

// playback. We don't release the media player because playback

// is likely to resume

if (mMediaPlayer.isPlaying()) mMediaPlayer.pause();

break;

case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:

// Lost focus for a short time, but it's ok to keep playing

// at an attenuated level

if (mMediaPlayer.isPlaying()) mMediaPlayer.setVolume(0.1f, 0.1f);

break;

}

}

public void onAudioFocusChange(int focusChange) {

switch (focusChange) {

case AudioManager.AUDIOFOCUS_GAIN:

// resume playback

if (mMediaPlayer == null) initMediaPlayer();

else if (!mMediaPlayer.isPlaying()) mMediaPlayer.start();

mMediaPlayer.setVolume(1.0f, 1.0f);

break;

case AudioManager.AUDIOFOCUS_LOSS:

// Lost focus for an unbounded amount of time: stop playback and release media player

if (mMediaPlayer.isPlaying()) mMediaPlayer.stop();

mMediaPlayer.release();

mMediaPlayer = null;

break;

case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:

// Lost focus for a short time, but we have to stop

// playback. We don't release the media player because playback

[!--empirenews.page--]

// is likely to resume

if (mMediaPlayer.isPlaying()) mMediaPlayer.pause();

break;

case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:

// Lost focus for a short time, but it's ok to keep playing

// at an attenuated level

if (mMediaPlayer.isPlaying()) mMediaPlayer.setVolume(0.1f, 0.1f);

break;

}

}

記住音頻焦點API僅在APIlevel 8 (Android2.2)及更高版本上可以,所以如果你想支持更早的Android版本,你必須在可能時采取兼容性的策略使用特性,如果不可能,you should adopt a backward compatibility strategy that allows you touse this feature if available, and fall back seamlessly if not.

你可以用反射的方式調(diào)用音頻焦點方法或自己在一個單獨的類(叫做AudioFocusHelper)中實現(xiàn)所有的音頻焦點功能來達(dá)到向前兼容.下面是一個這樣的類:

[java]

public class AudioFocusHelper implements AudioManager.OnAudioFocusChangeListener {

AudioManager mAudioManager;

// 這里是其它的字段,你可能要保存一個接口的引用,這個接口

// 被用于與你的service通訊以報告焦點的變化.

public AudioFocusHelper(Context ctx, ) {

mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);

// ...

}

public boolean requestFocus() {

return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==

mAudioManager.requestAudioFocus(mContext, AudioManager.STREAM_MUSIC,

AudioManager.AUDIOFOCUS_GAIN);

}

public boolean abandonFocus() {

return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==

mAudioManager.abandonAudioFocus(this);

}

@Override

public void onAudioFocusChange(int focusChange) {

// 讓你的service知道焦點變化了

}

}

你可以僅在檢測到系統(tǒng)運行的是API level 8 或更早的版本時才創(chuàng)建AudioFocusHelper類的實例.例如:

if (android.os.Build.VERSION.SDK_INT >= 8) {

mAudioFocusHelper = new AudioFocusHelper(getApplicationContext(), this);

} else {

mAudioFocusHelper = null;

}

public class AudioFocusHelper implements AudioManager.OnAudioFocusChangeListener {

AudioManager mAudioManager;

// 這里是其它的字段,你可能要保存一個接口的引用,這個接口

// 被用于與你的service通訊以報告焦點的變化.

public AudioFocusHelper(Context ctx, ) {

mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);

// ...

}

public boolean requestFocus() {

return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==

mAudioManager.requestAudioFocus(mContext, AudioManager.STREAM_MUSIC,

AudioManager.AUDIOFOCUS_GAIN);

}

public boolean abandonFocus() {

return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==

mAudioManager.abandonAudioFocus(this);

}

@Override

public void onAudioFocusChange(int focusChange) {

// 讓你的service知道焦點變化了

}

}

你可以僅在檢測到系統(tǒng)運行的是API level 8 或更早的版本時才創(chuàng)建AudioFocusHelper類的實例.例如:

if (android.os.Build.VERSION.SDK_INT >= 8) {

mAudioFocusHelper = new AudioFocusHelper(getApplicationContext(), this);

} else {

mAudioFocusHelper = null;

}

清理

前面提到過,一個MediaPlayer對象可以消耗掉大量的系統(tǒng)資源,所以你應(yīng)該僅在需要它時保持它并在用完時立即釋放.明確的調(diào)用清理方法而不是依靠系統(tǒng)的垃圾收集機(jī)制是很重要的,因為在被收集之前MediaPlayer可能會存在很長時間,雖然此時它只是占用內(nèi)存而不影響其它的媒體相關(guān)的資源.所以,當(dāng)你使用一個service時,你應(yīng)該總四重寫onDestroy()方法來保證釋放MediaPlayer:

[java]

public class MyService extends Service {

MediaPlayer mMediaPlayer;

// ...

@Override

public void onDestroy() {

if (mMediaPlayer != null) mMediaPlayer.release();

}

}

public class MyService extends Service {

MediaPlayer mMediaPlayer;

// ...

@Override

public void onDestroy() {

if (mMediaPlayer != null) mMediaPlayer.release();

}www.2cto.com

}

你也應(yīng)該尋找其它需要釋放你的MediaPlayer的時機(jī).例如,如果你預(yù)料到長時間不能播放媒體(比如丟掉音頻焦點以后),你應(yīng)該明確地釋放你的MediaPlayer,然后在后面重新創(chuàng)建它.反過來,如果你預(yù)測到只會短時間停止播放,你應(yīng)該保持你的MediaPlayer來避免過多的創(chuàng)建,而不是重新"準(zhǔn)備"它.

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉