Android 中封裝優(yōu)雅的 MediaPlayer 音頻播放器,支持多個(gè)播放器實(shí)例的示例:
public class AudioPlayer implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener {
private static AudioPlayer instance;
private List<AudioPlayerListener> listeners = new ArrayList<>();
private MediaPlayer mediaPlayer;
private Context context;
private AudioPlayer(Context context) {
this.context = context;
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnCompletionListener(this);
}
public static synchronized AudioPlayer getInstance(Context context) {
if (instance == null) {
instance = new AudioPlayer(context);
}
return instance;
}
public void addListener(AudioPlayerListener listener) {
listeners.add(listener);
}
public void removeListener(AudioPlayerListener listener) {
listeners.remove(listener);
}
public void play(String url) {
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stop() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
}
public void release() {
mediaPlayer.release();
}
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
for (AudioPlayerListener listener : listeners) {
listener.onAudioPlayerStart();
}
}
@Override
public void onCompletion(MediaPlayer mp) {
for (AudioPlayerListener listener : listeners) {
listener.onAudioPlayerStop();
}
}
public interface AudioPlayerListener {
void onAudioPlayerStart();
void onAudioPlayerStop();
}
}
上述代碼中,使用 getInstance()
方法獲取 AudioPlayer
的單例對(duì)象,參數(shù)傳入 Context
對(duì)象。
在 getInstance()
方法中判斷單例對(duì)象是否為空,如果為空則創(chuàng)建新的 AudioPlayer
對(duì)象,否則返回已有的單例對(duì)象。
這樣可以保證在同一進(jìn)程中,只有一個(gè) AudioPlayer
實(shí)例,方便管理多個(gè)音頻文件的播放。
該類有一個(gè) AudioPlayerListener
接口,用于監(jiān)聽播放器的狀態(tài)。在播放器的 onPrepared()
和 onCompletion()
方法中觸發(fā)回調(diào),通知所有監(jiān)聽器。
可以通過調(diào)用 addListener()
和 removeListener()
方法添加或移除監(jiān)聽器。
調(diào)用 play()
方法以播放音頻,傳入音頻的 URL 地址,調(diào)用 stop()
方法以停止播放,調(diào)用 release()
方法以釋放播放器資源。
可以按照以下步驟來調(diào)用單例模式的 AudioPlayer
類:
- 在需要使用
AudioPlayer
的地方,先獲取Context
對(duì)象,例如在MainActivity
中:
public class MainActivity extends AppCompatActivity {
private AudioPlayer audioPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
audioPlayer = AudioPlayer.getInstance(this);
}
//...
}
2.添加一個(gè) AudioPlayerListener
接口的實(shí)現(xiàn),監(jiān)聽音頻播放開始和結(jié)束事件:
public class MainActivity extends AppCompatActivity implements AudioPlayer.AudioPlayerListener {
// ...
@Override
public void onAudioPlayerStart() {
// 音頻播放開始
}
@Override
public void onAudioPlayerStop() {
// 音頻播放結(jié)束
}
}
3.在需要播放音頻的地方,調(diào)用 AudioPlayer
的 play()
方法:
audioPlayer.play(url);
其中,url
是音頻文件的 URL 地址。
4.在需要停止音頻播放的地方,調(diào)用 AudioPlayer
的 stop()
方法:
audioPlayer.stop();
如果需要釋放 MediaPlayer
實(shí)例,可以調(diào)用 AudioPlayer
的 release()
方法:
audioPlayer.release();
5.通過 addListener()
和 removeListener()
方法,添加和刪除 AudioPlayerListener
的實(shí)現(xiàn),監(jiān)聽音頻播放事件:
audioPlayer.addListener(this);
audioPlayer.removeListener(this);
這樣就可以使用單例模式的 AudioPlayer
類播放音頻了。需要注意的是,由于單例實(shí)例只有一個(gè),調(diào)用 release()
方法時(shí)要謹(jǐn)慎,避免對(duì)其他地方的音頻播放產(chǎn)生影響。
為了避免對(duì)其他地方的音頻播放產(chǎn)生影響,可以在 AudioPlayer
類中添加一些控制音頻焦點(diǎn)的方法。
這里需要用到 AudioManager
類,該類提供了訪問音頻系統(tǒng)服務(wù)的方法,可以控制應(yīng)用程序的音頻會(huì)話和音頻路由。
具體實(shí)現(xiàn)如下:
public class AudioPlayer implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, AudioManager.OnAudioFocusChangeListener {
private static AudioPlayer instance;
private List<AudioPlayerListener> listeners = new ArrayList<>();
private MediaPlayer mediaPlayer;
private Context context;
private AudioManager audioManager;
private boolean audioFocusGranted = false;
private AudioPlayer(Context context) {
this.context = context;
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnCompletionListener(this);
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
}
public static synchronized AudioPlayer getInstance(Context context) {
if (instance == null) {
instance = new AudioPlayer(context);
}
return instance;
}
public void addListener(AudioPlayerListener listener) {
listeners.add(listener);
}
public void removeListener(AudioPlayerListener listener) {
listeners.remove(listener);
}
public void play(String url) {
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();
requestAudioFocus();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stop() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
abandonAudioFocus();
}
public void release() {
stop();
mediaPlayer.release();
}
private void requestAudioFocus() {
if (!audioFocusGranted) {
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
audioFocusGranted = result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
}
private void abandonAudioFocus() {
if (audioFocusGranted) {
audioManager.abandonAudioFocus(this);
audioFocusGranted = false;
}
}
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
for (AudioPlayerListener listener : listeners) {
listener.onAudioPlayerStart();
}
}
@Override
public void onCompletion(MediaPlayer mp) {
for (AudioPlayerListener listener : listeners) {
listener.onAudioPlayerStop();
}
abandonAudioFocus();
}
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
mediaPlayer.start();
break;
case AudioManager.AUDIOFOCUS_LOSS:
stop();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
mediaPlayer.pause();
break;
}
}
public interface AudioPlayerListener {
void onAudioPlayerStart();
void onAudioPlayerStop();
}
}
上述代碼中:
-
audioManager
對(duì)象通過getSystemService()
方法獲取AUDIO_SERVICE
服務(wù)來初始化; -
play()
方法在播放音頻之前請(qǐng)求音頻焦點(diǎn); -
stop()
方法在停止播放音頻之后釋放音頻焦點(diǎn); -
requestAudioFocus()
方法用于請(qǐng)求音頻焦點(diǎn),當(dāng)焦點(diǎn)可用時(shí),音頻焦點(diǎn)授權(quán)標(biāo)志audioFocusGranted
會(huì)被設(shè)置為 true; -
abandonAudioFocus()
方法用于釋放音頻焦點(diǎn),當(dāng)焦點(diǎn)被釋放后,音頻焦點(diǎn)授權(quán)標(biāo)志audioFocusGranted
會(huì)被設(shè)置為 false; -
onAudioFocusChange()
方法在焦點(diǎn)發(fā)生變化時(shí)被調(diào)用,根據(jù)不同的焦點(diǎn)變化類型采取不同的處理方式; - 在
onCompletion()
方法中,當(dāng)音頻播放完成后,釋放音頻焦點(diǎn)。
這種實(shí)現(xiàn)方式可以滿足大多數(shù)情況,但仍可能存在一些問題,例如:
- 當(dāng)多個(gè)音頻焦點(diǎn)請(qǐng)求同時(shí)發(fā)生時(shí),可能會(huì)發(fā)生競(jìng)爭(zhēng)問題;
- 不同設(shè)備上的音頻焦點(diǎn)分配方式可能不同,可能需要進(jìn)行額外的適配。
因此,實(shí)現(xiàn)完美控制音頻焦點(diǎn)的方式需要根據(jù)具體情況進(jìn)行調(diào)整和完善。
在多個(gè)音頻焦點(diǎn)請(qǐng)求同時(shí)發(fā)生時(shí),可能會(huì)發(fā)生競(jìng)爭(zhēng)問題,最終的效果可能不如預(yù)期。為了優(yōu)化競(jìng)爭(zhēng)問題,可以考慮以下兩種方案:
-
策略模式:通過策略模式,我們可以將不同音頻焦點(diǎn)請(qǐng)求的處理方式分開,對(duì)不同的請(qǐng)求進(jìn)行不同的處理。這樣,可以避免彼此之間產(chǎn)生競(jìng)爭(zhēng)問題。同時(shí),策略模式可以方便地?cái)U(kuò)展新的音頻焦點(diǎn)策略。
-
優(yōu)先級(jí)系統(tǒng):通過優(yōu)先級(jí)系統(tǒng),我們可以為不同的音頻焦點(diǎn)請(qǐng)求設(shè)置不同的優(yōu)先級(jí),當(dāng)多個(gè)請(qǐng)求同時(shí)到達(dá)時(shí),根據(jù)優(yōu)先級(jí)依次處理,避免競(jìng)爭(zhēng)或者其他問題的發(fā)生。
同時(shí),還有一些額外的技巧可以使用:
-
隊(duì)列處理:當(dāng)多個(gè)音頻焦點(diǎn)請(qǐng)求同時(shí)到達(dá)時(shí),可以通過隊(duì)列處理,先進(jìn)先出的方式,避免競(jìng)爭(zhēng)或沖突的發(fā)生。
-
回調(diào)處理:當(dāng)多個(gè)音頻焦點(diǎn)請(qǐng)求同時(shí)到達(dá)時(shí),可以通過回調(diào)處理,當(dāng)某個(gè)請(qǐng)求處理完成后再處理下一個(gè)請(qǐng)求,避免發(fā)生競(jìng)爭(zhēng)或沖突的發(fā)生。
綜上所述,無論采用策略模式還是優(yōu)先級(jí)系統(tǒng),隊(duì)列處理還是回調(diào)處理,處理多個(gè)音頻焦點(diǎn)請(qǐng)求時(shí)應(yīng)選一具有優(yōu)化性能和處理方式清晰度的方法。
以下是一個(gè)簡(jiǎn)單的示例代碼,使用優(yōu)先級(jí)系統(tǒng)來處理多個(gè)音頻焦點(diǎn)請(qǐng)求:
public class AudioFocusManager {
private final List<AudioFocusRequest> requests = new ArrayList<>(); // 待處理的音頻焦點(diǎn)請(qǐng)求列表
public void requestAudioFocus(AudioFocusRequest request) {
requests.add(request); // 將請(qǐng)求加入待處理列表
Collections.sort(requests, new AudioFocusRequestComparator()); // 按照優(yōu)先級(jí)排序
processRequests(); // 處理請(qǐng)求
}
private void processRequests() {
AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
for (AudioFocusRequest request : requests) {
int result = audioManager.requestAudioFocus(request.getOnAudioFocusChangeListener(),
request.getStreamType(), request.getDurationHint());
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// 請(qǐng)求被拒絕
break;
} else {
// 請(qǐng)求被接受,處理下一個(gè)請(qǐng)求
requests.remove(request);
}
}
}
private static class AudioFocusRequestComparator implements Comparator<AudioFocusRequest> {
@Override
public int compare(AudioFocusRequest r1, AudioFocusRequest r2) {
return r2.getPriority() - r1.getPriority();
}
}
}
在上述代碼中,我們定義了一個(gè)AudioFocusManager
類來處理多個(gè)音頻焦點(diǎn)請(qǐng)求。當(dāng)我們調(diào)用requestAudioFocus
方法時(shí),將請(qǐng)求加入待處理列表,然后按照優(yōu)先級(jí)排序,依次處理請(qǐng)求。如果請(qǐng)求被拒絕,則停止處理,否則繼續(xù)處理下一個(gè)請(qǐng)求。
值得注意的是,此處假設(shè)AudioFocusRequest
已經(jīng)實(shí)現(xiàn)。具體實(shí)現(xiàn)方式可以根據(jù)實(shí)際業(yè)務(wù)需求來定制。例如,可以使用策略模式來實(shí)現(xiàn)不同音頻焦點(diǎn)請(qǐng)求的處理方式,或者使用回調(diào)來更新 UI 界面等。
要使用一個(gè)類似于上述示例中的音頻焦點(diǎn)管理器,以下是一些步驟:
- 創(chuàng)建一個(gè)名為
AudioFocusRequest
的類,該類應(yīng)該具有以下屬性和方法:
-
priority
- 請(qǐng)求的優(yōu)先級(jí),以整數(shù)形式表示 -
durationHint
- 請(qǐng)求的持續(xù)時(shí)間,以毫秒為單位 -
streamType
- 請(qǐng)求的音頻類型(例如,STREAM_MUSIC
) -
onAudioFocusChangeListener
- 處理焦點(diǎn)變化的監(jiān)聽器。您可以選擇使用內(nèi)部類來實(shí)現(xiàn)它。
-
創(chuàng)建一個(gè)名為
AudioFocusManager
的類,在該類中,編寫一個(gè)requestAudioFocus
方法,該方法接受一個(gè)AudioFocusRequest
對(duì)象,將其添加到一個(gè)列表中,并使用優(yōu)先級(jí)排序算法對(duì)待處理的請(qǐng)求進(jìn)行排序。然后,進(jìn)行請(qǐng)求處理并跟蹤列表中未處理的其他請(qǐng)求。 -
在需要管理音頻焦點(diǎn)的 Activity 中,實(shí)例化一個(gè)
AudioFocusManager
對(duì)象,并在需要獲取音頻焦點(diǎn)的地方調(diào)用requestAudioFocus
方法,傳入一個(gè)已經(jīng)實(shí)例化好的AudioFocusRequest
對(duì)象即可。
這樣,您的應(yīng)用程序?qū)⒛軌蛴行У乜刂埔纛l焦點(diǎn),并處理多個(gè)請(qǐng)求。
以下是一個(gè)簡(jiǎn)單的示例,演示如何使用上述步驟來管理音頻焦點(diǎn)。
首先,創(chuàng)建名為AudioFocusRequest
的 Java 類,該類應(yīng)該具有以下屬性和方法:
public class AudioFocusRequest {
private int priority;
private int durationHint;
private int streamType;
private OnAudioFocusChangeListener onAudioFocusChangeListener;
public AudioFocusRequest(int priority, int durationHint, int streamType, OnAudioFocusChangeListener onAudioFocusChangeListener) {
this.priority = priority;
this.durationHint = durationHint;
this.streamType = streamType;
this.onAudioFocusChangeListener = onAudioFocusChangeListener;
}
public int getPriority() {
return priority;
}
public int getDurationHint() {
return durationHint;
}
public int getStreamType() {
return streamType;
}
public OnAudioFocusChangeListener getOnAudioFocusChangeListener() {
return onAudioFocusChangeListener;
}
}
然后,創(chuàng)建名為AudioFocusManager
的 Java 類,并編寫一個(gè)requestAudioFocus
方法,代碼如下所示:
public class AudioFocusManager {
private List<AudioFocusRequest> audioFocusRequests = new ArrayList<>();
public void requestAudioFocus(AudioFocusRequest audioFocusRequest) {
audioFocusRequests.add(audioFocusRequest);
Collections.sort(audioFocusRequests, new Comparator<AudioFocusRequest>() {
@Override
public int compare(AudioFocusRequest r1, AudioFocusRequest r2) {
return r2.getPriority() - r1.getPriority();
}
});
processAudioFocusRequests();
}
private void processAudioFocusRequests() {
for (int i = 0; i < audioFocusRequests.size(); i++) {
AudioFocusRequest audioFocusRequest = audioFocusRequests.get(i);
int result = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
if (audioManager != null) {
result = audioManager.requestAudioFocus(audioFocusRequest.getOnAudioFocusChangeListener(),
audioFocusRequest.getStreamType(), audioFocusRequest.getDurationHint());
}
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
audioFocusRequests.remove(audioFocusRequest);
}
}
}
}
最后,您可以在需要管理音頻焦點(diǎn)的 Activity 中,按照示例代碼中的方式來使用AudioFocusManager
和AudioFocusRequest
,例如:
AudioFocusRequest audioFocusRequest = new AudioFocusRequest(AudioManager.AUDIOFOCUS_GAIN, 1000, AudioManager.STREAM_MUSIC, new OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
// 處理音頻焦點(diǎn)變化
}
});
AudioFocusManager audioFocusManager = new AudioFocusManager();
audioFocusManager.requestAudioFocus(audioFocusRequest);
在此示例中,我們創(chuàng)建了一個(gè)AudioFocusRequest
對(duì)象, 使用AudioFocusManager
請(qǐng)求音頻焦點(diǎn),并指定處理請(qǐng)求的回調(diào)方法。
以下是一個(gè)使用AudioFocusManager類來處理多個(gè)音頻焦點(diǎn)請(qǐng)求的示例代碼:
public class AudioFocusManager implements AudioManager.OnAudioFocusChangeListener {
private AudioManager audioManager;
private Map<AudioFocusRequest, AudioFocusChangeListener> audioFocusRequests;
public AudioFocusManager(Context context) {
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
audioFocusRequests = new HashMap<>();
}
public void requestAudioFocus(AudioFocusRequest audioFocusRequest, AudioFocusChangeListener audioFocusChangeListener) {
audioFocusRequests.put(audioFocusRequest, audioFocusChangeListener);
updateAudioFocus();
}
public void abandonAudioFocus(AudioFocusRequest audioFocusRequest) {
audioFocusRequests.remove(audioFocusRequest);
updateAudioFocus();
}
private void updateAudioFocus() {
AudioFocusRequest topAudioFocusRequest = getTopAudioFocusRequest();
if (topAudioFocusRequest == null) {
audioManager.abandonAudioFocus(this);
} else {
int focusRequestResult = audioManager.requestAudioFocus(
topAudioFocusRequest.getAudioFocusRequest(),
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
if (focusRequestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
AudioFocusChangeListener audioFocusChangeListener = audioFocusRequests.get(topAudioFocusRequest);
if (audioFocusChangeListener != null) {
audioFocusChangeListener.onAudioFocusChanged(true);
}
}
}
}
private AudioFocusRequest getTopAudioFocusRequest() {
AudioFocusRequest topAudioFocusRequest = null;
for (AudioFocusRequest audioFocusRequest : audioFocusRequests.keySet()) {
if (topAudioFocusRequest == null || audioFocusRequest.getPriority() > topAudioFocusRequest.getPriority()) {
topAudioFocusRequest = audioFocusRequest;
}
}
return topAudioFocusRequest;
}
@Override
public void onAudioFocusChange(int focusChange) {
AudioFocusRequest topAudioFocusRequest = getTopAudioFocusRequest();
if (topAudioFocusRequest != null) {
AudioFocusChangeListener audioFocusChangeListener = audioFocusRequests.get(topAudioFocusRequest);
if (audioFocusChangeListener != null) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
audioFocusChangeListener.onAudioFocusChanged(true);
break;
case AudioManager.AUDIOFOCUS_LOSS:
audioFocusRequests.clear();
audioFocusChangeListener.onAudioFocusChanged(false);
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
audioFocusChangeListener.onAudioFocusChanged(false);
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
audioFocusChangeListener.onAudioFocusChanged(false);
break;
}
}
}
}
public interface AudioFocusChangeListener {
void onAudioFocusChanged(boolean hasAudioFocus);
}
public static class AudioFocusRequest {
private final int priority;
private final AudioAttributes audioAttributes;
public AudioFocusRequest(int priority, AudioAttributes audioAttributes) {
this.priority = priority;
this.audioAttributes = audioAttributes;
}
public int getPriority() {
return priority;
}
public AudioAttributes getAudioAttributes() {
return audioAttributes;
}
public androidx.media.AudioAttributesCompat getAudioAttributesCompat() {
return androidx.media.AudioAttributesCompat.wrap(audioAttributes);
}
public AudioFocusRequestCompat getAudioFocusRequestCompat() {
return new AudioFocusRequestCompat.Builder(getPriority())
.setAudioAttributes(getAudioAttributesCompat())
.build();
}
public AudioFocusRequest getAudioFocusRequest() {
return new AudioFocusRequest.Builder(getPriority())
.setAudioAttributes(audioAttributes)
.build();
}
}
}
這個(gè)示例代碼中的AudioFocusManager
類包含以下方法:
-
requestAudioFocus(AudioFocusRequest audioFocusRequest, AudioFocusChangeListener audioFocusChangeListener)
:向系統(tǒng)請(qǐng)求音頻焦點(diǎn),并提供了一個(gè)回調(diào)函數(shù)來通知應(yīng)用程序當(dāng)音頻焦點(diǎn)狀態(tài)改變時(shí)。多次調(diào)用此方法將根據(jù)請(qǐng)求的優(yōu)先級(jí)來處理多個(gè)音頻焦點(diǎn)請(qǐng)求。 -
abandonAudioFocus(AudioFocusRequest audioFocusRequest)
:放棄音頻焦點(diǎn),并在內(nèi)部更新所有請(qǐng)求焦點(diǎn)的對(duì)象列表。 -
updateAudioFocus()
:根據(jù)當(dāng)前優(yōu)先級(jí)的順序使用AudioManager
請(qǐng)求音頻焦點(diǎn),在焦點(diǎn)狀態(tài)改變時(shí)通知相應(yīng)的監(jiān)聽者。 -
getTopAudioFocusRequest()
:返回一個(gè)包含最高優(yōu)先級(jí)的AudioFocusRequest
對(duì)象。 - `onAudioFocus
以下是一個(gè)使用AudioFocusManager
類來處理多個(gè)音頻焦點(diǎn)請(qǐng)求的完整示例代碼:
public class MainActivity extends AppCompatActivity {
private AudioFocusManager audioFocusManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
audioFocusManager = new AudioFocusManager(this);
}
@Override
protected void onStart() {
super.onStart();
AudioFocusManager.AudioFocusRequest audioFocusRequest1 = new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build());
AudioFocusManager.AudioFocusRequest audioFocusRequest2 = new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build());
audioFocusManager.requestAudioFocus(audioFocusRequest1, new AudioFocusManager.AudioFocusChangeListener() {
@Override
public void onAudioFocusChanged(boolean hasAudioFocus) {
if (hasAudioFocus) {
// 開始播放音樂
} else {
// 暫?;蛲V挂魳凡シ? }
}
});
audioFocusManager.requestAudioFocus(audioFocusRequest2, new AudioFocusManager.AudioFocusChangeListener() {
@Override
public void onAudioFocusChanged(boolean hasAudioFocus) {
if (hasAudioFocus) {
// 播放通知提示音
} else {
// 停止播放通知提示音
}
}
});
}
@Override
protected void onStop() {
super.onStop();
audioFocusManager.abandonAudioFocus(new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()));
audioFocusManager.abandonAudioFocus(new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build()));
}
}
在這個(gè)示例中,我們?cè)?code>MainActivity的onStart()
方法中請(qǐng)求了兩種不同類型的音頻焦點(diǎn):AudioFocusRequest
對(duì)象audioFocusRequest1
和audioFocusRequest2
,它們分別代表媒體播放和通知提示音。我們還為每個(gè)焦點(diǎn)請(qǐng)求設(shè)置了對(duì)應(yīng)的AudioFocusChangeListener
來處理焦點(diǎn)狀態(tài)的變化。
在MainActivity
的onStop()
方法中我們請(qǐng)求釋放這兩種音頻焦點(diǎn)。
如果需要同時(shí)管理多個(gè)不同的播放器(如同時(shí)播放背景音樂、音效和語音提示等),可以通過實(shí)例化多個(gè)AudioFocusManager
類來實(shí)現(xiàn),每個(gè)類只負(fù)責(zé)管理一個(gè)播放器。需要注意的是,多個(gè)AudioFocusManager
實(shí)例之間的焦點(diǎn)請(qǐng)求和變化都是獨(dú)立的,因此需要在適當(dāng)?shù)臅r(shí)候根據(jù)自己的業(yè)務(wù)邏輯進(jìn)行相應(yīng)的協(xié)調(diào)。
以下是一個(gè)同時(shí)管理三個(gè)播放器的簡(jiǎn)單示例代碼:
public class MainActivity extends AppCompatActivity {
private AudioFocusManager mediaPlayer1FocusManager;
private AudioFocusManager mediaPlayer2FocusManager;
private AudioFocusManager mediaPlayer3FocusManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mediaPlayer1FocusManager = new AudioFocusManager(this);
mediaPlayer2FocusManager = new AudioFocusManager(this);
mediaPlayer3FocusManager = new AudioFocusManager(this);
}
@Override
protected void onStart() {
super.onStart();
AudioFocusManager.AudioFocusRequest audioFocusRequest1 = new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build());
AudioFocusManager.AudioFocusRequest audioFocusRequest2 = new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build());
AudioFocusManager.AudioFocusRequest audioFocusRequest3 = new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build());
mediaPlayer1FocusManager.requestAudioFocus(audioFocusRequest1, new AudioFocusManager.AudioFocusChangeListener() {
@Override
public void onAudioFocusChanged(boolean hasAudioFocus) {
if (hasAudioFocus) {
// 開始播放媒體音樂
} else {
// 暫停或停止媒體音樂播放
}
}
});
mediaPlayer2FocusManager.requestAudioFocus(audioFocusRequest2, new AudioFocusManager.AudioFocusChangeListener() {
@Override
public void onAudioFocusChanged(boolean hasAudioFocus) {
if (hasAudioFocus) {
// 開始播放游戲音效
} else {
// 停止播放游戲音效
}
}
});
mediaPlayer3FocusManager.requestAudioFocus(audioFocusRequest3, new AudioFocusManager.AudioFocusChangeListener() {
@Override
public void onAudioFocusChanged(boolean hasAudioFocus) {
if (hasAudioFocus) {
// 開始播放語音提示
} else {
// 停止播放語音提示
}
}
});
}
@Override
protected void onStop() {
super.onStop();
mediaPlayer1FocusManager.abandonAudioFocus(new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()));
mediaPlayer2FocusManager.abandonAudioFocus(new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build()));
mediaPlayer3FocusManager.abandonAudioFocus(new AudioFocusManager.AudioFocusRequest(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build()));
}
}
在這個(gè)示例中,我們實(shí)例化了三個(gè)AudioFocusManager
對(duì)象來依次處理三個(gè)不同的播放器。每個(gè)播放器都有自己的焦點(diǎn)請(qǐng)求和對(duì)應(yīng)的焦點(diǎn)狀態(tài)監(jiān)聽器。在onStart()
方法中,我們通過這三個(gè)焦點(diǎn)管理器分別請(qǐng)求了不同的音頻焦點(diǎn)。在onStop()
方法中,我們則請(qǐng)求釋放三種不同的音
如果你想在前面示例中使用已經(jīng)封裝好的AudioPlayer
來播放音頻文件,可以按照以下步驟進(jìn)行修改:
- 創(chuàng)建一個(gè)
AudioPlayer
對(duì)象。
AudioPlayer audioPlayer = new AudioPlayer();
- 在獲取音頻焦點(diǎn)后,使用
AudioPlayer
對(duì)象播放音頻文件,示例代碼如下: -
mediaPlayer1FocusManager.requestAudioFocus(audioFocusRequest1, new AudioFocusManager.AudioFocusChangeListener() { @Override public void onAudioFocusChanged(boolean hasAudioFocus) { if (hasAudioFocus) { // 開始播放媒體音樂 audioPlayer.play(MainActivity.this, R.raw.background_music); } else { // 暫?;蛲V姑襟w音樂播放 audioPlayer.stop(); } } });
- 在對(duì)應(yīng)的停止音頻播放的位置,調(diào)用
AudioPlayer
對(duì)象的stop()
方法停止當(dāng)前播放的音頻文件: -
audioPlayer.stop();
如果需要播放多個(gè)音頻文件,可以根據(jù)需要重復(fù)上述步驟,每次創(chuàng)建一個(gè)新的
AudioPlayer
對(duì)象并調(diào)用相應(yīng)的方法來實(shí)現(xiàn)。 -
下面是結(jié)合
AudioFocusManager
的完整示例代碼:
public class AudioPlayer implements AudioFocusManager.AudioFocusListener {
private static AudioPlayer instance;
private HashMap<Integer, MediaPlayer> mediaPlayerMap;
private AudioFocusManager audioFocusManager;
private AudioPlayer(Context context) {
mediaPlayerMap = new HashMap<>();
audioFocusManager = new AudioFocusManager(context, this);
}
public static synchronized AudioPlayer getInstance(Context context) {
if (instance == null) {
instance = new AudioPlayer(context);
}
return instance;
}
public void play(Context context, int resId, boolean looping) {
if (mediaPlayerMap.containsKey(resId)) {
MediaPlayer mediaPlayer = mediaPlayerMap.get(resId);
mediaPlayer.setLooping(looping);
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
} else {
MediaPlayer mediaPlayer = MediaPlayer.create(context, resId);
mediaPlayerMap.put(resId, mediaPlayer);
mediaPlayer.setLooping(looping);
mediaPlayer.start();
}
audioFocusManager.requestAudioFocus();
}
public void pause(int resId) {
if (mediaPlayerMap.containsKey(resId)) {
MediaPlayer mediaPlayer = mediaPlayerMap.get(resId);
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
}
public void stop(int resId) {
if (mediaPlayerMap.containsKey(resId)) {
MediaPlayer mediaPlayer = mediaPlayerMap.get(resId);
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
mediaPlayerMap.remove(resId);
}
audioFocusManager.abandonAudioFocus();
}
public void stopAll() {
for (MediaPlayer mediaPlayer : mediaPlayerMap.values()) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
}
mediaPlayerMap.clear();
audioFocusManager.abandonAudioFocus();
}
@Override
public void onAudioFocusGained() {
// do nothing
}
@Override
public void onAudioFocusLost() {
stopAll();
}
@Override
public void onAudioFocusLostTransient() {
stopAll();
}
@Override
public void onAudioFocusLostTransientCanDuck() {
// do nothing
}
}
在上面的代碼中,我們將 AudioPlayer
實(shí)現(xiàn)為單例模式,然后我們將 AudioFocusManager
添加到 AudioPlayer
類中,以控制音頻焦點(diǎn)。
在 play()
方法中,我們先根據(jù) looping
參數(shù)在 Map 中查詢是否已存在所需音頻的 MediaPlayer 對(duì)象。如果存在,則設(shè)置循環(huán)播放屬性并開始播放;否則,我們創(chuàng)建一個(gè)新的 MediaPlayer 對(duì)象并將其添加到 Map 中。接著,我們使用 requestAudioFocus()
方法請(qǐng)求音頻焦點(diǎn)以確保我們可以正常播放該音頻。
在 stop()
和 stopAll()
方法中,我們先停止所有的 MediaPlayer 對(duì)象并釋放它們占用的資源。接著,我們使用 abandonAudioFocus()
方法歸還我們之前請(qǐng)求的音頻焦點(diǎn)。
最后,在 AudioFocusListener
的回調(diào)方法中,我們根據(jù)不同的焦點(diǎn)失去情況來停止播放。
這就是結(jié)合 AudioFocusManager
的 AudioPlayer
完整示例代碼。希望能夠幫助你實(shí)現(xiàn)你的音頻播放器。
下面是使用 AudioPlayer
類播放音頻的示例代碼:
public class MainActivity extends AppCompatActivity {
private AudioPlayer audioPlayer;
private int audioResId = R.raw.audio_file;
private boolean isLooping = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
audioPlayer = AudioPlayer.getInstance(this);
}
public void onClickPlay(View view) {
audioPlayer.play(this, audioResId, isLooping);
}
public void onClickPause(View view) {
audioPlayer.pause(audioResId);
}
public void onClickStop(View view) {
audioPlayer.stop(audioResId);
}
public void onClickStopAll(View view) {
audioPlayer.stopAll();
}
}
在上面的代碼中,我們首先在 onCreate()
方法中獲取 AudioPlayer
實(shí)例。接著,在處理用戶交互時(shí),例如點(diǎn)擊各種按鈕時(shí),我們調(diào)用 AudioPlayer
類中相應(yīng)的方法,以播放、暫停或停止音頻。
當(dāng)用戶點(diǎn)擊 "Play" 按鈕時(shí),我們使用 play()
方法請(qǐng)求音頻焦點(diǎn)并播放音頻。當(dāng)用戶點(diǎn)擊 "Pause" 按鈕時(shí),我們使用 pause()
方法暫停音頻的播放。當(dāng)用戶點(diǎn)擊 "Stop" 按鈕時(shí),我們使用 stop()
方法停止音頻的播放并釋放占用的資源。當(dāng)用戶點(diǎn)擊 "Stop All" 按鈕時(shí),我們使用 stopAll()
方法來停止播放所有音頻并同時(shí)釋放占用的資源。文章來源:http://www.zghlxwxcb.cn/news/detail-518354.html
這就是使用 AudioPlayer
類播放音頻的示例代碼。希望它能幫助你實(shí)現(xiàn)你的音頻播放器應(yīng)用程序。文章來源地址http://www.zghlxwxcb.cn/news/detail-518354.html
到了這里,關(guān)于Android 中封裝優(yōu)雅的 MediaPlayer 音頻播放器,支持多個(gè)播放器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!