Android 中封装优雅的 MediaPlayer 音频播放器,支持多个播放器

这篇具有很好参考价值的文章主要介绍了Android 中封装优雅的 MediaPlayer 音频播放器,支持多个播放器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Android 中封装优雅的 MediaPlayer 音频播放器,支持多个播放器实例的示例:

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 的单例对象,参数传入 Context 对象。

getInstance() 方法中判断单例对象是否为空,如果为空则创建新的 AudioPlayer 对象,否则返回已有的单例对象。

这样可以保证在同一进程中,只有一个 AudioPlayer 实例,方便管理多个音频文件的播放。

该类有一个 AudioPlayerListener 接口,用于监听播放器的状态。在播放器的 onPrepared()onCompletion() 方法中触发回调,通知所有监听器。

可以通过调用 addListener()removeListener() 方法添加或移除监听器。

调用 play() 方法以播放音频,传入音频的 URL 地址,调用 stop() 方法以停止播放,调用 release() 方法以释放播放器资源。

可以按照以下步骤来调用单例模式的 AudioPlayer 类:

  1. 在需要使用 AudioPlayer 的地方,先获取 Context 对象,例如在 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.添加一个 AudioPlayerListener 接口的实现,监听音频播放开始和结束事件:

public class MainActivity extends AppCompatActivity implements AudioPlayer.AudioPlayerListener {

    // ...

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

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

3.在需要播放音频的地方,调用 AudioPlayerplay() 方法:

audioPlayer.play(url);

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

4.在需要停止音频播放的地方,调用 AudioPlayerstop() 方法:

 
audioPlayer.stop();

如果需要释放 MediaPlayer 实例,可以调用 AudioPlayerrelease() 方法:

audioPlayer.release();

5.通过 addListener()removeListener() 方法,添加和删除 AudioPlayerListener 的实现,监听音频播放事件:

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

这样就可以使用单例模式的 AudioPlayer 类播放音频了。需要注意的是,由于单例实例只有一个,调用 release() 方法时要谨慎,避免对其他地方的音频播放产生影响。

为了避免对其他地方的音频播放产生影响,可以在 AudioPlayer 类中添加一些控制音频焦点的方法。

这里需要用到 AudioManager 类,该类提供了访问音频系统服务的方法,可以控制应用程序的音频会话和音频路由。

具体实现如下:

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 对象通过 getSystemService() 方法获取 AUDIO_SERVICE 服务来初始化;
  2. play() 方法在播放音频之前请求音频焦点;
  3. stop() 方法在停止播放音频之后释放音频焦点;
  4. requestAudioFocus() 方法用于请求音频焦点,当焦点可用时,音频焦点授权标志 audioFocusGranted 会被设置为 true;
  5. abandonAudioFocus() 方法用于释放音频焦点,当焦点被释放后,音频焦点授权标志 audioFocusGranted 会被设置为 false;
  6. onAudioFocusChange() 方法在焦点发生变化时被调用,根据不同的焦点变化类型采取不同的处理方式;
  7. onCompletion() 方法中,当音频播放完成后,释放音频焦点。

这种实现方式可以满足大多数情况,但仍可能存在一些问题,例如:

  1. 当多个音频焦点请求同时发生时,可能会发生竞争问题;
  2. 不同设备上的音频焦点分配方式可能不同,可能需要进行额外的适配。

因此,实现完美控制音频焦点的方式需要根据具体情况进行调整和完善。

在多个音频焦点请求同时发生时,可能会发生竞争问题,最终的效果可能不如预期。为了优化竞争问题,可以考虑以下两种方案:

  1. 策略模式:通过策略模式,我们可以将不同音频焦点请求的处理方式分开,对不同的请求进行不同的处理。这样,可以避免彼此之间产生竞争问题。同时,策略模式可以方便地扩展新的音频焦点策略。

  2. 优先级系统:通过优先级系统,我们可以为不同的音频焦点请求设置不同的优先级,当多个请求同时到达时,根据优先级依次处理,避免竞争或者其他问题的发生。

同时,还有一些额外的技巧可以使用:

  1. 队列处理:当多个音频焦点请求同时到达时,可以通过队列处理,先进先出的方式,避免竞争或冲突的发生。

  2. 回调处理:当多个音频焦点请求同时到达时,可以通过回调处理,当某个请求处理完成后再处理下一个请求,避免发生竞争或冲突的发生。

综上所述,无论采用策略模式还是优先级系统,队列处理还是回调处理,处理多个音频焦点请求时应选一具有优化性能和处理方式清晰度的方法。

以下是一个简单的示例代码,使用优先级系统来处理多个音频焦点请求:

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

在上述代码中,我们定义了一个AudioFocusManager类来处理多个音频焦点请求。当我们调用requestAudioFocus方法时,将请求加入待处理列表,然后按照优先级排序,依次处理请求。如果请求被拒绝,则停止处理,否则继续处理下一个请求。

值得注意的是,此处假设AudioFocusRequest已经实现。具体实现方式可以根据实际业务需求来定制。例如,可以使用策略模式来实现不同音频焦点请求的处理方式,或者使用回调来更新 UI 界面等。

要使用一个类似于上述示例中的音频焦点管理器,以下是一些步骤:

  1. 创建一个名为AudioFocusRequest的类,该类应该具有以下属性和方法:
  • priority - 请求的优先级,以整数形式表示
  • durationHint - 请求的持续时间,以毫秒为单位
  • streamType - 请求的音频类型(例如,STREAM_MUSIC
  • onAudioFocusChangeListener - 处理焦点变化的监听器。您可以选择使用内部类来实现它。
  1. 创建一个名为AudioFocusManager的类,在该类中,编写一个requestAudioFocus方法,该方法接受一个AudioFocusRequest对象,将其添加到一个列表中,并使用优先级排序算法对待处理的请求进行排序。然后,进行请求处理并跟踪列表中未处理的其他请求。

  2. 在需要管理音频焦点的 Activity 中,实例化一个AudioFocusManager对象,并在需要获取音频焦点的地方调用requestAudioFocus方法,传入一个已经实例化好的AudioFocusRequest对象即可。

这样,您的应用程序将能够有效地控制音频焦点,并处理多个请求。

以下是一个简单的示例,演示如何使用上述步骤来管理音频焦点。

首先,创建名为AudioFocusRequest的 Java 类,该类应该具有以下属性和方法:

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

然后,创建名为AudioFocusManager的 Java 类,并编写一个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);
            }
        }
    }
}

最后,您可以在需要管理音频焦点的 Activity 中,按照示例代码中的方式来使用AudioFocusManagerAudioFocusRequest,例如:

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

在此示例中,我们创建了一个AudioFocusRequest对象, 使用AudioFocusManager请求音频焦点,并指定处理请求的回调方法。

以下是一个使用AudioFocusManager类来处理多个音频焦点请求的示例代码:

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

这个示例代码中的AudioFocusManager类包含以下方法:

  • requestAudioFocus(AudioFocusRequest audioFocusRequest, AudioFocusChangeListener audioFocusChangeListener):向系统请求音频焦点,并提供了一个回调函数来通知应用程序当音频焦点状态改变时。多次调用此方法将根据请求的优先级来处理多个音频焦点请求。
  • abandonAudioFocus(AudioFocusRequest audioFocusRequest):放弃音频焦点,并在内部更新所有请求焦点的对象列表。
  • updateAudioFocus():根据当前优先级的顺序使用AudioManager请求音频焦点,在焦点状态改变时通知相应的监听者。
  • getTopAudioFocusRequest():返回一个包含最高优先级的AudioFocusRequest对象。
  • `onAudioFocus

以下是一个使用AudioFocusManager类来处理多个音频焦点请求的完整示例代码:

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

在这个示例中,我们在MainActivityonStart()方法中请求了两种不同类型的音频焦点:AudioFocusRequest对象audioFocusRequest1audioFocusRequest2,它们分别代表媒体播放和通知提示音。我们还为每个焦点请求设置了对应的AudioFocusChangeListener来处理焦点状态的变化。

MainActivityonStop()方法中我们请求释放这两种音频焦点。

如果需要同时管理多个不同的播放器(如同时播放背景音乐、音效和语音提示等),可以通过实例化多个AudioFocusManager类来实现,每个类只负责管理一个播放器。需要注意的是,多个AudioFocusManager实例之间的焦点请求和变化都是独立的,因此需要在适当的时候根据自己的业务逻辑进行相应的协调。

以下是一个同时管理三个播放器的简单示例代码:

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

在这个示例中,我们实例化了三个AudioFocusManager对象来依次处理三个不同的播放器。每个播放器都有自己的焦点请求和对应的焦点状态监听器。在onStart()方法中,我们通过这三个焦点管理器分别请求了不同的音频焦点。在onStop()方法中,我们则请求释放三种不同的音

如果你想在前面示例中使用已经封装好的AudioPlayer来播放音频文件,可以按照以下步骤进行修改:

  1. 创建一个AudioPlayer对象。

AudioPlayer audioPlayer = new AudioPlayer();

  1. 在获取音频焦点后,使用AudioPlayer对象播放音频文件,示例代码如下:
  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. 在对应的停止音频播放的位置,调用AudioPlayer对象的stop()方法停止当前播放的音频文件:
  4.  

    audioPlayer.stop();

    如果需要播放多个音频文件,可以根据需要重复上述步骤,每次创建一个新的AudioPlayer对象并调用相应的方法来实现。

  5. 下面是结合 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 实现为单例模式,然后我们将 AudioFocusManager 添加到 AudioPlayer 类中,以控制音频焦点。

play() 方法中,我们先根据 looping 参数在 Map 中查询是否已存在所需音频的 MediaPlayer 对象。如果存在,则设置循环播放属性并开始播放;否则,我们创建一个新的 MediaPlayer 对象并将其添加到 Map 中。接着,我们使用 requestAudioFocus() 方法请求音频焦点以确保我们可以正常播放该音频。

stop()stopAll() 方法中,我们先停止所有的 MediaPlayer 对象并释放它们占用的资源。接着,我们使用 abandonAudioFocus() 方法归还我们之前请求的音频焦点。

最后,在 AudioFocusListener 的回调方法中,我们根据不同的焦点失去情况来停止播放。

这就是结合 AudioFocusManagerAudioPlayer 完整示例代码。希望能够帮助你实现你的音频播放器。

下面是使用 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 实例。接着,在处理用户交互时,例如点击各种按钮时,我们调用 AudioPlayer 类中相应的方法,以播放、暂停或停止音频。

当用户点击 "Play" 按钮时,我们使用 play() 方法请求音频焦点并播放音频。当用户点击 "Pause" 按钮时,我们使用 pause() 方法暂停音频的播放。当用户点击 "Stop" 按钮时,我们使用 stop() 方法停止音频的播放并释放占用的资源。当用户点击 "Stop All" 按钮时,我们使用 stopAll() 方法来停止播放所有音频并同时释放占用的资源。

这就是使用 AudioPlayer 类播放音频的示例代码。希望它能帮助你实现你的音频播放器应用程序。文章来源地址https://www.toymoban.com/news/detail-518354.html

到了这里,关于Android 中封装优雅的 MediaPlayer 音频播放器,支持多个播放器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Vue实现自定义音频播放器组件

    template javascript less 文档参考 关于 Audio 自定义样式 H5 audio 音频标签自定义样式修改以及添加播放控制事件

    2024年02月12日
    浏览(37)
  • 用selenium爬取直播信息,前端音频播放器

    #保存数据的函数 def save_data(self,data_list,i): #在当前目录下将数据存为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页保存完成!” % i) (2)保存为json文件 #保存数据的函数 def save_data(self,data_list,i): with op

    2024年04月16日
    浏览(50)
  • 一个WPF开发的、界面简洁漂亮的音频播放器

    今天推荐一个界面简洁、美观的、支持国际化开源音频播放器。 这是一个基于C# + WPF开发的,界面外观简洁大方,操作体验良好的音频播放器。 支持各种音频格式,包括:MP4、WMA、OGG、FLAC、M4A、AAC、WAV、APE 和 OPUS;支持标记、实时显示歌词等功能;支持换肤、中英文等主流

    2024年02月01日
    浏览(54)
  • Android 之 MediaPlayer 播放音频与视频

    本节带来的是Android多媒体中的——MediaPlayer,我们可以通过这个API来播放音频和视频 该类是Androd多媒体框架中的一个重要组件,通过该类,我们可以以最小的步骤来获取,解码 和播放音视频。它支持三种不同的媒体来源: 本地资源 内部的URI,比如你可以通过ContentResolver来获

    2024年02月13日
    浏览(36)
  • 音频播放器Web页面代码实例(基于HTML5)

    音频播放器Web页面代码实例(基于HTML5):   特别需要注意的点:     如果上传文件时设置的是默认转码方式,所有的文件都会转码为视频文件,使用音频播放器播放视频文件时,只会播放声音,没有图像。     如果上传文件时设置了\\\"源文件播放\\\",平台不会对源文件进行

    2024年02月16日
    浏览(39)
  • 基于 FFmpeg 的跨平台视频播放器简明教程(六):使用 SDL 播放音频和视频

    基于 FFmpeg 的跨平台视频播放器简明教程(一):FFMPEG + Conan 环境集成 基于 FFmpeg 的跨平台视频播放器简明教程(二):基础知识和解封装(demux) 基于 FFmpeg 的跨平台视频播放器简明教程(三):视频解码 基于 FFmpeg 的跨平台视频播放器简明教程(四):像素格式与格式转换

    2024年02月13日
    浏览(61)
  • html+css+js本地音乐播放器,实现可视化音频频谱

    html+css+js本地音乐播放器,实现可视化音频频谱 之前用swing写了个本地音乐播放器(如下图),但是效果一言难尽,界面丑,功能bug也多,唉 所以后面又重新用html写了个,界面样式和功能方面,比swing写的好看、完善多了。 导入音乐(已完成) 展示列表(已完成) 列表双击

    2024年02月09日
    浏览(54)
  • 腾讯二面:自动贩卖机/音频播放器使用了什么设计模式?

    状态模式是什么? 状态模式,也被称作状态对象模式,是一种行为设计模式。 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类。 它让对象在其内部状态改变时改变自己的行为。外部调用者无需了解对象内部状态的具体实现,仅需通过简单的

    2024年01月20日
    浏览(40)
  • FFmpeg: 自实现ijkplayer播放器--06封装打开和关闭stream

    流程图 stream open 初始化SDL以允许⾳频输出; 初始化帧Frame队列 初始化包Packet队列 初始化时钟Clock 初始化音量 创建解复用读取线程read_thread 创建视频刷新线程video_refresh_thread

    2024年04月15日
    浏览(31)
  • Android 13.0 系统多个播放器app时,设置默认播放器

     在13.0的系统产品开发中,对于在系统中有多个播放器的时候,这时候如果调用代码打开播放器,会出现多个播放器列表让用户 选择启动哪个播放器,所以产品开发需求需要设置默认播放器,当打开播放器的时候,就直接打开播放器就可以了,所以就需要 了解查询播放器列

    2024年02月08日
    浏览(73)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包