国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Android 中封裝優(yōu)雅的 MediaPlayer 音頻播放器,支持多個(gè)播放器

這篇具有很好參考價(jià)值的文章主要介紹了Android 中封裝優(yōu)雅的 MediaPlayer 音頻播放器,支持多個(gè)播放器。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

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 類:

  1. 在需要使用 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)用 AudioPlayerplay() 方法:

audioPlayer.play(url);

其中,url 是音頻文件的 URL 地址。

4.在需要停止音頻播放的地方,調(diào)用 AudioPlayerstop() 方法:

 
audioPlayer.stop();

如果需要釋放 MediaPlayer 實(shí)例,可以調(diào)用 AudioPlayerrelease() 方法:

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();
    }
}

上述代碼中:

  1. audioManager 對(duì)象通過 getSystemService() 方法獲取 AUDIO_SERVICE 服務(wù)來初始化;
  2. play() 方法在播放音頻之前請(qǐng)求音頻焦點(diǎn);
  3. stop() 方法在停止播放音頻之后釋放音頻焦點(diǎn);
  4. requestAudioFocus() 方法用于請(qǐng)求音頻焦點(diǎn),當(dāng)焦點(diǎn)可用時(shí),音頻焦點(diǎn)授權(quán)標(biāo)志 audioFocusGranted 會(huì)被設(shè)置為 true;
  5. abandonAudioFocus() 方法用于釋放音頻焦點(diǎn),當(dāng)焦點(diǎn)被釋放后,音頻焦點(diǎn)授權(quán)標(biāo)志 audioFocusGranted 會(huì)被設(shè)置為 false;
  6. onAudioFocusChange() 方法在焦點(diǎn)發(fā)生變化時(shí)被調(diào)用,根據(jù)不同的焦點(diǎn)變化類型采取不同的處理方式;
  7. onCompletion() 方法中,當(dāng)音頻播放完成后,釋放音頻焦點(diǎn)。

這種實(shí)現(xiàn)方式可以滿足大多數(shù)情況,但仍可能存在一些問題,例如:

  1. 當(dāng)多個(gè)音頻焦點(diǎn)請(qǐng)求同時(shí)發(fā)生時(shí),可能會(huì)發(fā)生競(jìng)爭(zhēng)問題;
  2. 不同設(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)問題,可以考慮以下兩種方案:

  1. 策略模式:通過策略模式,我們可以將不同音頻焦點(diǎn)請(qǐng)求的處理方式分開,對(duì)不同的請(qǐng)求進(jìn)行不同的處理。這樣,可以避免彼此之間產(chǎn)生競(jìng)爭(zhēng)問題。同時(shí),策略模式可以方便地?cái)U(kuò)展新的音頻焦點(diǎn)策略。

  2. 優(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í),還有一些額外的技巧可以使用:

  1. 隊(duì)列處理:當(dāng)多個(gè)音頻焦點(diǎn)請(qǐng)求同時(shí)到達(dá)時(shí),可以通過隊(duì)列處理,先進(jìn)先出的方式,避免競(jìng)爭(zhēng)或沖突的發(fā)生。

  2. 回調(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)管理器,以下是一些步驟:

  1. 創(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)它。
  1. 創(chuàng)建一個(gè)名為AudioFocusManager的類,在該類中,編寫一個(gè)requestAudioFocus方法,該方法接受一個(gè)AudioFocusRequest對(duì)象,將其添加到一個(gè)列表中,并使用優(yōu)先級(jí)排序算法對(duì)待處理的請(qǐng)求進(jìn)行排序。然后,進(jìn)行請(qǐng)求處理并跟蹤列表中未處理的其他請(qǐng)求。

  2. 在需要管理音頻焦點(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 中,按照示例代碼中的方式來使用AudioFocusManagerAudioFocusRequest,例如:

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ì)象audioFocusRequest1audioFocusRequest2,它們分別代表媒體播放和通知提示音。我們還為每個(gè)焦點(diǎn)請(qǐng)求設(shè)置了對(duì)應(yīng)的AudioFocusChangeListener來處理焦點(diǎn)狀態(tài)的變化。

MainActivityonStop()方法中我們請(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)行修改:

  1. 創(chuàng)建一個(gè)AudioPlayer對(duì)象。

AudioPlayer audioPlayer = new AudioPlayer();

  1. 在獲取音頻焦點(diǎn)后,使用AudioPlayer對(duì)象播放音頻文件,示例代碼如下:
  2. 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();
            }
        }
    });
    
  3. 在對(duì)應(yīng)的停止音頻播放的位置,調(diào)用AudioPlayer對(duì)象的stop()方法停止當(dāng)前播放的音頻文件:
  4.  

    audioPlayer.stop();

    如果需要播放多個(gè)音頻文件,可以根據(jù)需要重復(fù)上述步驟,每次創(chuàng)建一個(gè)新的AudioPlayer對(duì)象并調(diào)用相應(yīng)的方法來實(shí)現(xiàn)。

  5. 下面是結(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é)合 AudioFocusManagerAudioPlayer 完整示例代碼。希望能夠幫助你實(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í)釋放占用的資源。

這就是使用 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)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Vue實(shí)現(xiàn)自定義音頻播放器組件

    Vue實(shí)現(xiàn)自定義音頻播放器組件

    template javascript less 文檔參考 關(guān)于 Audio 自定義樣式 H5 audio 音頻標(biāo)簽自定義樣式修改以及添加播放控制事件

    2024年02月12日
    瀏覽(20)
  • 用selenium爬取直播信息,前端音頻播放器

    用selenium爬取直播信息,前端音頻播放器

    #保存數(shù)據(jù)的函數(shù) def save_data(self,data_list,i): #在當(dāng)前目錄下將數(shù)據(jù)存為txt文件 with open(‘./douyu.txt’,‘w’,encoding=‘utf-8’) as fp: for data in data_list: data = str(data) fp.write(data+‘n’) print(“第%d頁(yè)保存完成!” % i) (2)保存為json文件 #保存數(shù)據(jù)的函數(shù) def save_data(self,data_list,i): with op

    2024年04月16日
    瀏覽(18)
  • 一個(gè)WPF開發(fā)的、界面簡(jiǎn)潔漂亮的音頻播放器

    一個(gè)WPF開發(fā)的、界面簡(jiǎn)潔漂亮的音頻播放器

    今天推薦一個(gè)界面簡(jiǎn)潔、美觀的、支持國(guó)際化開源音頻播放器。 這是一個(gè)基于C# + WPF開發(fā)的,界面外觀簡(jiǎn)潔大方,操作體驗(yàn)良好的音頻播放器。 支持各種音頻格式,包括:MP4、WMA、OGG、FLAC、M4A、AAC、WAV、APE 和 OPUS;支持標(biāo)記、實(shí)時(shí)顯示歌詞等功能;支持換膚、中英文等主流

    2024年02月01日
    瀏覽(48)
  • Android 之 MediaPlayer 播放音頻與視頻

    Android 之 MediaPlayer 播放音頻與視頻

    本節(jié)帶來的是Android多媒體中的——MediaPlayer,我們可以通過這個(gè)API來播放音頻和視頻 該類是Androd多媒體框架中的一個(gè)重要組件,通過該類,我們可以以最小的步驟來獲取,解碼 和播放音視頻。它支持三種不同的媒體來源: 本地資源 內(nèi)部的URI,比如你可以通過ContentResolver來獲

    2024年02月13日
    瀏覽(20)
  • 音頻播放器Web頁(yè)面代碼實(shí)例(基于HTML5)

    音頻播放器Web頁(yè)面代碼實(shí)例(基于HTML5)

    音頻播放器Web頁(yè)面代碼實(shí)例(基于HTML5): ? 特別需要注意的點(diǎn): ??? 如果上傳文件時(shí)設(shè)置的是默認(rèn)轉(zhuǎn)碼方式,所有的文件都會(huì)轉(zhuǎn)碼為視頻文件,使用音頻播放器播放視頻文件時(shí),只會(huì)播放聲音,沒有圖像。 ??? 如果上傳文件時(shí)設(shè)置了\\\"源文件播放\\\",平臺(tái)不會(huì)對(duì)源文件進(jìn)行

    2024年02月16日
    瀏覽(28)
  • 基于 FFmpeg 的跨平臺(tái)視頻播放器簡(jiǎn)明教程(六):使用 SDL 播放音頻和視頻

    基于 FFmpeg 的跨平臺(tái)視頻播放器簡(jiǎn)明教程(六):使用 SDL 播放音頻和視頻

    基于 FFmpeg 的跨平臺(tái)視頻播放器簡(jiǎn)明教程(一):FFMPEG + Conan 環(huán)境集成 基于 FFmpeg 的跨平臺(tái)視頻播放器簡(jiǎn)明教程(二):基礎(chǔ)知識(shí)和解封裝(demux) 基于 FFmpeg 的跨平臺(tái)視頻播放器簡(jiǎn)明教程(三):視頻解碼 基于 FFmpeg 的跨平臺(tái)視頻播放器簡(jiǎn)明教程(四):像素格式與格式轉(zhuǎn)換

    2024年02月13日
    瀏覽(124)
  • 騰訊二面:自動(dòng)販賣機(jī)/音頻播放器使用了什么設(shè)計(jì)模式?

    騰訊二面:自動(dòng)販賣機(jī)/音頻播放器使用了什么設(shè)計(jì)模式?

    狀態(tài)模式是什么? 狀態(tài)模式,也被稱作狀態(tài)對(duì)象模式,是一種行為設(shè)計(jì)模式。 當(dāng)一個(gè)對(duì)象的內(nèi)在狀態(tài)改變時(shí),允許改變其行為,這個(gè)對(duì)象看起來像是改變了其類。 它讓對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變自己的行為。外部調(diào)用者無需了解對(duì)象內(nèi)部狀態(tài)的具體實(shí)現(xiàn),僅需通過簡(jiǎn)單的

    2024年01月20日
    瀏覽(33)
  • html+css+js本地音樂播放器,實(shí)現(xiàn)可視化音頻頻譜

    html+css+js本地音樂播放器,實(shí)現(xiàn)可視化音頻頻譜

    html+css+js本地音樂播放器,實(shí)現(xiàn)可視化音頻頻譜 之前用swing寫了個(gè)本地音樂播放器(如下圖),但是效果一言難盡,界面丑,功能bug也多,唉 所以后面又重新用html寫了個(gè),界面樣式和功能方面,比swing寫的好看、完善多了。 導(dǎo)入音樂(已完成) 展示列表(已完成) 列表雙擊

    2024年02月09日
    瀏覽(29)
  • FFmpeg: 自實(shí)現(xiàn)ijkplayer播放器--06封裝打開和關(guān)閉stream

    FFmpeg: 自實(shí)現(xiàn)ijkplayer播放器--06封裝打開和關(guān)閉stream

    流程圖 stream open 初始化SDL以允許?頻輸出; 初始化幀F(xiàn)rame隊(duì)列 初始化包Packet隊(duì)列 初始化時(shí)鐘Clock 初始化音量 創(chuàng)建解復(fù)用讀取線程read_thread 創(chuàng)建視頻刷新線程video_refresh_thread

    2024年04月15日
    瀏覽(24)
  • Android 13.0 系統(tǒng)多個(gè)播放器app時(shí),設(shè)置默認(rèn)播放器

    ?在13.0的系統(tǒng)產(chǎn)品開發(fā)中,對(duì)于在系統(tǒng)中有多個(gè)播放器的時(shí)候,這時(shí)候如果調(diào)用代碼打開播放器,會(huì)出現(xiàn)多個(gè)播放器列表讓用戶 選擇啟動(dòng)哪個(gè)播放器,所以產(chǎn)品開發(fā)需求需要設(shè)置默認(rèn)播放器,當(dāng)打開播放器的時(shí)候,就直接打開播放器就可以了,所以就需要 了解查詢播放器列

    2024年02月08日
    瀏覽(55)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包