Android Foreground Service 中,提示音循环播放及停止

文章目录

    需求背景

    Android App 收到蓝牙推送的消息之后,播放提示音,且一直播放,直到收到停止的指令。

    TODO

    • [X] fragment 界面上增加两个按钮:开始,停止。方便测试
    • [X] 提取出播放和停止功能,封装成两个函数。便于测试
    • [X] 接收到停止指令后,关闭音频
    • [X] Foreground Service 中定义 LiveData,方便 fragment 点击按钮后操作。实际不需要,直接在 service 中定义成静态方法即可。
    • [X] 下载报警提示音
    • [X] 支持自定义音频文件。这个以后播放引导提示音频也能用到,只不过是只用一次
    • [X] 测试无误后,去掉开始按钮(隐藏),只保留停止按钮。按钮名称,关闭警报提示音

    下载报警提示音

    https://pixabay.com/sound-effects/search/alert/

    在 Android Studio 项目的 res 目录下,新建一个 raw 目录,将下载到的 mp3 音频文件放进去。

    例如,命名为 alert.mp3

    播放报警提示音

    由于是在 Foreground Service 中播放音频,所以为了方便 fragment 中调用,使用了静态变量和方法。

    同时 Foreground Service 的静态方法中无法获取 context,所以加上了 Context 参数。

    private static MediaPlayer mediaPlayer;
    
    public static void playAlertAudio(Context context) {
    	if (mediaPlayer != null && mediaPlayer.isPlaying()) {
    		// 防止重复播放
    		return;
    	}
    
    	mediaPlayer = MediaPlayer.create(context, R.raw.alert);
    	mediaPlayer.setLooping(true);
    	mediaPlayer.start();
    }
    

    停止播放

    public static void stopAlertAudio() {
    	if (mediaPlayer != null && mediaPlayer.isPlaying()) {
    		mediaPlayer.stop();
    		mediaPlayer.reset();
    	}
    }
    

    Foreground Servie 中调用

    BLE 监听回调中:

    NodeConnectionService.playAlertAudio(getApplicationContext());
    

    Fragment 中调用

    按钮点击事件中:

    NodeConnectionService.playAlertAudio(getContext());
    

    华为鸿蒙系统上的诡异问题

    这个功能在台电的 Android 平板上及小米手机上运行的很正常,但是在华为鸿蒙的平板上,有明显的问题。

    就是如果信号源短时间内发送了多个报警,这个音频停不下来,或是同时播放了多个音频。即过滤没有成功。

    增加了两项针对性的改进:

    • 使用自己的标识位标识是否在播放中
    • 为了防止 mediaPlayer 初始化慢,将标识位放在初始化前

    修改后的代码:

        private static MediaPlayer mediaPlayer;
        private static boolean isPlayingAlert = false;
    
        public static void playAlertAudio(Context context) {
            if (mediaPlayer != null && isPlayingAlert) {
                // 防止重复播放
                return;
            }
    
            isPlayingAlert = true;
    
            mediaPlayer = MediaPlayer.create(context, R.raw.alert);
    
            mediaPlayer.setLooping(true);
            mediaPlayer.start();
    
        }
    
        public static void stopAlertAudio() {
            if (mediaPlayer != null && isPlayingAlert) {
                mediaPlayer.stop();
                mediaPlayer.reset();
                isPlayingAlert = false;
            }
        }
    

    关于作者 🌱

    我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式