Um elegante reprodutor de áudio MediaPlayer encapsulado em Android, com suporte a vários reprodutores

Um exemplo de um elegante reprodutor de áudio MediaPlayer empacotado em Android que suporta múltiplas instâncias de reprodutor:

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

No código acima, o objeto singleton getInstance()é obtido usando o método e os parâmetros são passados ​​no objeto.AudioPlayerContext

No getInstance()método, determine se o objeto singleton está vazio. Se estiver vazio, crie um novo AudioPlayerobjeto, caso contrário, retorne o objeto singleton existente.

AudioPlayerIsso garante que haja apenas uma instância no mesmo processo , facilitando o gerenciamento da reprodução de vários arquivos de áudio.

Esta classe possui uma AudioPlayerListenerinterface para monitorar o status do player. Acione retornos de chamada no player onPrepared()e onCompletion()métodos para notificar todos os ouvintes.

Os ouvintes podem ser adicionados ou removidos chamando os métodos addListener()e .removeListener()

Chame play()o método para reproduzir o áudio, passe o endereço URL do áudio, chame stop()o método para interromper a reprodução e chame release()o método para liberar os recursos do player.

Você pode seguir as etapas abaixo para chamar uma classe no modo singleton AudioPlayer:

  1. Onde você precisar usar AudioPlayer, primeiro obtenha Contexto objeto, por exemplo em 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. Adicione uma AudioPlayerListenerimplementação da interface para monitorar eventos de início e término da reprodução de áudio:

public class MainActivity extends AppCompatActivity implements AudioPlayer.AudioPlayerListener {

    // ...

    @Override
    public void onAudioPlayerStart() {
        // 音频播放开始
    }

    @Override
    public void onAudioPlayerStop() {
        // 音频播放结束
    }
}

3. Onde você precisar reproduzir áudio, chame AudioPlayero play()método:

audioPlayer.play(url);

Entre eles urlestá o endereço URL do arquivo de áudio.

4. Onde a reprodução de áudio precisar ser interrompida, chame o método AudioPlayerde stop():

 
 
audioPlayer.stop();

Se precisar liberar MediaPlayera instância, você pode chamar o método AudioPlayerde release():

audioPlayer.release();

5. Através addListener()dos métodos e removeListener(), adicione e exclua AudioPlayerListenerimplementações e monitore eventos de reprodução de áudio:

audioPlayer.addListener(this); 
audioPlayer.removeListener(this);

Dessa forma, você pode usar a AudioPlayerclasse de modo singleton para reproduzir áudio. Deve-se observar que, como existe apenas uma instância singleton, release()tome cuidado ao chamar o método para evitar afetar a reprodução de áudio em outro lugar.

Para evitar afetar a reprodução de áudio em outros lugares, você pode AudioPlayeradicionar alguns métodos para controlar o foco do áudio na classe.

Você precisa usar a classe aqui AudioManager, que fornece métodos para acessar os serviços do sistema de áudio e pode controlar a sessão de áudio e o roteamento de áudio do aplicativo.

A implementação específica é a seguinte:

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

No código acima:

  1. audioManagergetSystemService()O objeto é inicializado obtendo o serviço através do método AUDIO_SERVICE;
  2. play()Método para solicitar foco de áudio antes de reproduzir áudio;
  3. stop()O método libera o foco do áudio após interromper a reprodução do áudio;
  4. requestAudioFocus()O método é usado para solicitar foco de áudio.Quando o foco estiver disponível, o sinalizador de autorização de foco de áudio audioFocusGrantedserá definido como verdadeiro;
  5. abandonAudioFocus()O método é usado para liberar o foco de áudio. Quando o foco é liberado, o sinalizador de autorização do foco de áudio audioFocusGrantedserá definido como falso;
  6. onAudioFocusChange()O método é chamado quando o foco muda e diferentes métodos de processamento são adotados de acordo com os diferentes tipos de mudança de foco;
  7. No onCompletion()método, quando a reprodução do áudio for concluída, libere o foco do áudio.

Esta implementação pode satisfazer a maioria das situações, mas ainda pode haver alguns problemas, tais como:

  1. Podem ocorrer problemas de corrida quando múltiplas solicitações de foco de áudio ocorrem simultaneamente;
  2. O foco de áudio pode ser alocado de forma diferente em dispositivos diferentes e pode exigir adaptações adicionais.

Portanto, a forma de obter um controle perfeito sobre o foco do áudio precisa ser adaptada e refinada caso a caso.

Quando várias solicitações de foco de áudio ocorrem simultaneamente, podem ocorrer condições de corrida e o resultado final pode não ser o esperado. Para otimizar o problema de concorrência, podem ser consideradas as duas opções seguintes:

  1. Modo de estratégia: Através do modo de estratégia, podemos separar os métodos de processamento de diferentes solicitações de foco de áudio e processar diferentes solicitações de maneira diferente. Desta forma, podem ser evitados problemas de concorrência entre si. Ao mesmo tempo, o Modo Estratégia facilita a extensão de novas estratégias de foco de áudio.

  2. Sistema de prioridade: Através do sistema de prioridade, podemos definir diferentes prioridades para diferentes solicitações de foco de áudio. Quando várias solicitações chegam ao mesmo tempo, elas serão processadas em ordem de acordo com a prioridade para evitar concorrência ou outros problemas.

Enquanto isso, existem alguns truques adicionais que você pode usar:

  1. Processamento de fila: quando várias solicitações de foco de áudio chegam ao mesmo tempo, elas podem ser processadas em uma fila e primeiro a entrar, primeiro a sair para evitar competição ou conflitos.

  2. Processamento de retorno de chamada: quando várias solicitações de foco de áudio chegam ao mesmo tempo, o processamento de retorno de chamada pode ser usado. Quando uma solicitação é processada, a próxima solicitação pode ser processada para evitar competição ou conflito.

Em resumo, quer você use o modo de política ou um sistema de prioridade, processamento de fila ou processamento de retorno de chamada, ao lidar com diversas solicitações de foco de áudio, você deve escolher um método que otimize o desempenho e a clareza do processamento.

Aqui está um exemplo de código simples que usa um sistema de prioridade para lidar com múltiplas solicitações de foco de áudio:

public class AudioFocusManager {
    
    private final List<AudioFocusRequest> requests = new ArrayList<>(); // 待处理的音频焦点请求列表
    
    public void requestAudioFocus(AudioFocusRequest request) {
        requests.add(request); // 将请求加入待处理列表
        Collections.sort(requests, new AudioFocusRequestComparator()); // 按照优先级排序
        processRequests(); // 处理请求
    }
    
    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) {
                // 请求被拒绝
                break;
            } else {
                // 请求被接受,处理下一个请求
                requests.remove(request);
            }
        }
    }
    
    private static class AudioFocusRequestComparator implements Comparator<AudioFocusRequest> {
        @Override
        public int compare(AudioFocusRequest r1, AudioFocusRequest r2) {
            return r2.getPriority() - r1.getPriority();
        }
    }
}

No código acima, definimos uma AudioFocusManagerclasse para lidar com múltiplas solicitações de foco de áudio. Quando chamamos requestAudioFocuso método, a solicitação é adicionada à lista pendente, depois classificada de acordo com a prioridade e as solicitações são processadas em ordem. Se a solicitação for rejeitada, o processamento será interrompido; caso contrário, o processamento continuará na próxima solicitação.

Vale ressaltar que as suposições aqui AudioFocusRequestsão cumpridas. O método de implementação específico pode ser personalizado de acordo com as necessidades reais do negócio. Por exemplo, você pode usar o padrão de estratégia para implementar como diferentes solicitações de foco de áudio são tratadas ou usar retornos de chamada para atualizar a interface da IU, etc.

Para usar um gerenciador de foco de áudio semelhante ao do exemplo acima, aqui estão algumas etapas:

  1. Crie uma AudioFocusRequestclasse chamada que deverá ter as seguintes propriedades e métodos:
  • priority- A prioridade da solicitação, expressa como um número inteiro
  • durationHint- A duração da solicitação em milissegundos
  • streamType- Tipo de áudio solicitado (por exemplo STREAM_MUSIC)
  • onAudioFocusChangeListener- Ouvintes que lidam com mudanças de foco. Você pode optar por usar uma classe interna para implementá-la.
  1. Crie uma AudioFocusManagerclasse chamada e, nessa classe, escreva um requestAudioFocusmétodo que aceite um AudioFocusRequestobjeto, adicione-o a uma lista e classifique as solicitações pendentes usando um algoritmo de priorização. Em seguida, faça o processamento da solicitação e acompanhe outras solicitações não processadas na lista.

  2. Na Activity que precisa gerenciar o foco de áudio, instancie um AudioFocusManagerobjeto e chame requestAudioFocuso método onde o foco de áudio precisa ser obtido, passando um AudioFocusRequestobjeto já instanciado.

Dessa forma, seu aplicativo será capaz de controlar com eficiência o foco do áudio e lidar com diversas solicitações.

Aqui está um exemplo simples que demonstra como gerenciar o foco do áudio usando as etapas acima.

Primeiro, crie AudioFocusRequestuma classe Java chamada , que deve ter as seguintes propriedades e métodos:

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

Em seguida, crie AudioFocusManageruma classe Java chamada e escreva um requestAudioFocusmétodo com o seguinte código:

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

AudioFocusManagerPor fim, você pode usar e conforme mostrado no código de exemplo na atividade que precisa gerenciar o foco de áudio AudioFocusRequest, por exemplo:

AudioFocusRequest audioFocusRequest = new AudioFocusRequest(AudioManager.AUDIOFOCUS_GAIN, 1000, AudioManager.STREAM_MUSIC, new OnAudioFocusChangeListener() {
    @Override
    public void onAudioFocusChange(int focusChange) {
        // 处理音频焦点变化
    }
});

AudioFocusManager audioFocusManager = new AudioFocusManager();
audioFocusManager.requestAudioFocus(audioFocusRequest);

Neste exemplo, criamos um AudioFocusRequestobjeto, usamos-o AudioFocusManagerpara solicitar foco de áudio e especificamos um método de retorno de chamada para tratar a solicitação.

A seguir está um exemplo de código que usa a classe AudioFocusManager para lidar com várias solicitações de foco de áudio:

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

A classe neste código de exemplo AudioFocusManagercontém os seguintes métodos:

  • requestAudioFocus(AudioFocusRequest audioFocusRequest, AudioFocusChangeListener audioFocusChangeListener): solicita foco de áudio do sistema e fornece uma função de retorno de chamada para notificar o aplicativo quando o estado do foco de áudio muda. Chamar esse método várias vezes tratará diversas solicitações de foco de áudio com base na prioridade das solicitações.
  • abandonAudioFocus(AudioFocusRequest audioFocusRequest):Renuncia ao foco de áudio e atualiza internamente a lista de todos os objetos que solicitam foco.
  • updateAudioFocus(): Use para solicitar foco de áudio de acordo com a ordem de prioridade atual AudioManagere notificar o ouvinte correspondente quando o status do foco mudar.
  • getTopAudioFocusRequest()AudioFocusRequest: Retorna um objeto contendo a prioridade mais alta .
  • `onAudioFocus

Aqui está um exemplo de código completo usando uma AudioFocusManagerclasse para lidar com múltiplas solicitações de foco de áudio:

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 {
                    // 暂停或停止音乐播放
                }
            }
        });

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

Neste exemplo, solicitamos MainActivitydois onStart()tipos diferentes de foco de áudio no método: AudioFocusRequestobjetos audioFocusRequest1e audioFocusRequest2, que representam reprodução de mídia e sons de notificação respectivamente. Também configuramos os correspondentes para cada solicitação de foco AudioFocusChangeListenerpara lidar com mudanças no estado de foco.

No MainActivitymétodo onStop()solicitamos a liberação de ambos os focos de áudio.

Se você precisar gerenciar vários players diferentes ao mesmo tempo (como reproduzir música de fundo, efeitos sonoros, comandos de voz, etc.) ao mesmo tempo, poderá instanciar várias classes. Cada classe é responsável apenas por gerenciar um player AudioFocusManager. Deve-se observar que AudioFocusManageras solicitações de foco e as alterações entre múltiplas instâncias são independentes, portanto, precisam ser coordenadas de acordo com sua própria lógica de negócios no momento apropriado.

Aqui está um exemplo de código simples para gerenciar três jogadores ao mesmo tempo:

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

Neste exemplo, instanciamos três AudioFocusManagerobjetos para lidar com três jogadores diferentes em sequência. Cada player tem sua própria solicitação de foco e ouvinte de estado de foco correspondente. No onStart()método, solicitamos diferentes focos de áudio por meio desses três gerenciadores de foco. No onStop()método solicitamos a liberação de três sons diferentes

Se quiser usar o AudioPlayerarquivo de áudio encapsulado do exemplo anterior para reproduzir o arquivo de áudio, você pode modificá-lo da seguinte maneira:

  1. Crie um AudioPlayerobjeto.

AudioPlayer audioPlayer = new AudioPlayer();

  1. Após obter o foco do áudio, use AudioPlayero objeto para reproduzir o arquivo de áudio. O código de exemplo é o seguinte:
  2. mediaPlayer1FocusManager.requestAudioFocus(audioFocusRequest1, new AudioFocusManager.AudioFocusChangeListener() {
        @Override
        public void onAudioFocusChanged(boolean hasAudioFocus) {
            if (hasAudioFocus) {
                // 开始播放媒体音乐
                audioPlayer.play(MainActivity.this, R.raw.background_music);
            } else {
                // 暂停或停止媒体音乐播放
                audioPlayer.stop();
            }
        }
    });
    

  3. Na posição correspondente para interromper a reprodução do áudio, chame AudioPlayero método do objeto stop()para interromper o arquivo de áudio atualmente sendo reproduzido:
  4.  

    audioPlayer.stop();

    Se precisar reproduzir vários arquivos de áudio, você pode repetir as etapas acima conforme necessário, criando um novo AudioPlayerobjeto a cada vez e chamando o método correspondente.

  5. Aqui está AudioFocusManagero código de exemplo completo combinado com:

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
    }
}

No código acima, implementamos AudioPlayercomo padrão singleton e, em seguida, adicionamos AudioFocusManagerà AudioPlayerclasse para controlar o foco do áudio.

No play()método, primeiro loopingconsultamos o Mapa de acordo com o parâmetro para verificar se o objeto MediaPlayer do áudio requerido já existe. Se existir, defina a propriedade loop playback e comece a reproduzir; caso contrário, criamos um novo objeto MediaPlayer e o adicionamos ao Mapa. A seguir, requestAudioFocus()solicitamos o foco do áudio usando o método para garantir que podemos reproduzir o áudio corretamente.

Nos métodos stop()e stopAll(), primeiro paramos todos os objetos MediaPlayer e liberamos os recursos que eles ocupam. A seguir, usamos abandonAudioFocus()o método para retornar o foco de áudio solicitado anteriormente.

Finalmente, no AudioFocusListenermétodo de retorno de chamada, interrompemos a reprodução de acordo com diferentes situações de perda de foco.

Este é o código de exemplo completo combinado AudioFocusManagercom . AudioPlayerEspero que isso ajude você a implementar seu reprodutor de áudio.

AudioPlayerAqui está um exemplo de código para reproduzir áudio usando a classe:

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

No código acima, primeiro onCreate()obtemos AudioPlayera instância no método. Então, ao lidar com a interação do usuário, como clicar em vários botões, chamamos os AudioPlayermétodos correspondentes na classe para reproduzir, pausar ou parar o áudio.

Quando o usuário clica no botão “Play”, utilizamos play()o método para solicitar o foco do áudio e reproduzir o áudio. Quando o usuário clica no botão “Pausar”, utilizamos pause()o método para pausar a reprodução do áudio. Quando o usuário clica no botão “Parar”, utilizamos stop()o método para interromper a reprodução do áudio e liberar os recursos ocupados. Quando o usuário clica no botão “Parar tudo”, utilizamos stopAll()o método para interromper a reprodução de todo o áudio e liberar os recursos ocupados ao mesmo tempo.

Este é AudioPlayerum exemplo de código para reproduzir áudio usando a classe. Espero que ajude você a implementar seu aplicativo reprodutor de áudio.

Acho que você gosta

Origin blog.csdn.net/ck3345143/article/details/129944532
Recomendado
Clasificación