Android16进阶之MediaPlayer.setLooping调用流程与实战(二百三十一)

简介: CSDN博客专家、《Android系统多媒体进阶实战》作者

博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列原创干货持续更新中...... 】🚀
Android多媒体专栏地址:多媒体系统工程师系列原创干货持续更新中...... 】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课 🚀
专题四:Android15快速自定义与集成音效实战课 🚀
专题五:Android15音频策略实战课 🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例) 🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

      • [🌻1. 前言](#🌻1. 前言)
      • [🌻2. 用法与应用场景](#🌻2. 用法与应用场景)
      • [🌻3. 调用流程剖析](#🌻3. 调用流程剖析)
        • [3.1 核心步骤](#3.1 核心步骤)
        • [3.2 涉及核心时序图](#3.2 涉及核心时序图)
      • [🌻4. 实战应用案例](#🌻4. 实战应用案例)
      • [🌻5. 用法总结](#🌻5. 用法总结)

🌻1. 前言

本篇目的:Android16音频深度解析之MediaPlayer.setLooping调用流程与实战。

在多媒体应用中,循环播放(Looping)是一个极其常见的需求,例如游戏的背景音乐、冥想类应用的白噪音或是手机铃声。MediaPlayer.setLooping 允许开发者通过一个简单的布尔值开关,控制媒体流在到达末尾时是立即停止并触发完成回调,还是自动跳转回起始点重新开始播放。


🌻2. 用法与应用场景

MediaPlayer.setLooping 方法用于设置播放器是否进入循环模式。

  • 用法说明 :该方法可以在 MediaPlayer 的任何状态下调用,但其逻辑生效是在播放到达媒体结束点(End of Stream)时。

  • 运行结果

  • true:播放结束后自动 Seek 到 0 并继续播放,不触发 OnCompletionListener

  • false:播放结束后停止,并触发 OnCompletionListener

  • 应用场景

  1. 游戏背景音乐:确保 BGM 在游戏运行期间不间断循环。
  2. 展厅引导语音:在公共场所循环播放特定的通知或导览信息。
  3. 短视频/GIF 播放:实现类似 TikTok 的短视频无限自动重播效果。

🌻3. 调用流程剖析

3.1 核心步骤
  1. Java 层参数透传MediaPlayer.java 接收 boolean 参数,并调用 native_setLooping 进入 JNI 层。
  2. Native 状态同步 :JNI 将指令分发给 mediaplayer.cpp,最终通过 Binder 封送到 MediaServer 进程中的播放引擎对象。
  3. 引擎标志位设定 :在 NuPlayer 引擎中,该标志位被存储在 SourcePlayer 的配置参数中。
  4. 边界检测(End of Stream) :当解码器读取到媒体文件的最后一个 Buffer 时,引擎会检查 mLooping 标志。
  5. 自动跳转指令 :如果循环开启,引擎不会向上层发送 MEDIA_PLAYBACK_COMPLETE 消息,而是内部执行一个 seekTo(0) 的原子操作,并刷新解码器缓冲区,直接开始新一轮的渲染。
3.2 涉及核心时序图

Decoder/Source NuPlayer Engine MediaPlayer Native MediaPlayer Java 应用代码层 Decoder/Source NuPlayer Engine MediaPlayer Native MediaPlayer Java 应用代码层 播放进行中... alt [Looping == true] [Looping == false] 调用 setLooping(true) 调用 native_setLooping 更新引擎循环标志位 发送流结束信号 (EOS) 检查 Looping 标志位 执行内部 SeekTo(0) 重新启动数据流读取 发送完成通知 触发 OnCompletionListener


🌻4. 实战应用案例

本案例展示了如何正确地在初始化阶段开启循环播放,并提供了一个动态切换循环模式的安全封装。

java 复制代码
public class LoopPlaybackManager {
    private MediaPlayer mediaPlayer;

    public void startBgm(Context context, Uri uri) {
        if (mediaPlayer == null) {
            mediaPlayer = new MediaPlayer();
        }
        try {
            mediaPlayer.setDataSource(context, uri);
            // 1. 在准备前或准备后均可设置,这里演示在准备前设置
            mediaPlayer.setLooping(true);
            
            mediaPlayer.setOnPreparedListener(mp -> {
                System.out.println("BGM 开始无限循环播放");
                mp.start();
            });
            mediaPlayer.prepareAsync();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据用户交互动态切换循环状态
     * @param shouldLoop 是否循环
     */
    public void toggleLooping(boolean shouldLoop) {
        if (mediaPlayer != null) {
            try {
                // 实时生效:如果在播放末尾切换,会立即改变下一次的行为
                mediaPlayer.setLooping(shouldLoop);
                boolean isNowLooping = mediaPlayer.isLooping();
                System.out.println("当前循环状态已更新为: " + isNowLooping);
            } catch (IllegalStateException e) {
                System.err.println("播放器处于非法状态,无法设置循环");
            }
        }
    }

    public void stopAndRelease() {
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }
}

🌻5. 用法总结

调用层级 核心职责 关键特性/影响
应用框架层 提供布尔值接口与状态获取 isLooping() 可随时查询当前模式
系统服务层 跨进程维护播放配置属性 确保参数在 MediaServer 侧实时同步
引擎处理层 执行边界逻辑判断与自动重置 屏蔽 onCompletion 事件,实现自动续播
解码驱动层 响应 flush 与重新定位指令 循环时需要重新初始化解码上下文
用户体验层 提供无缝的听感体验 循环间隔受文件开头/结尾静音段影响
相关推荐
Android系统攻城狮5 天前
Android tinyalsa深度解析之pcm_format_to_bits调用流程与实战(一百二十三)
android·pcm·tinyalsa·音频进阶·音频性能实战
Android系统攻城狮6 天前
Android tinyalsa深度解析之pcm_set_avail_min调用流程与实战(一百二十二)
android·pcm·tinyalsa·音频进阶·android hal·audio hal
Android系统攻城狮7 天前
Android tinyalsa深度解析之pcm_get_delay调用流程与实战(一百一十九)
android·pcm·tinyalsa·音频进阶·android hal·audio hal
Android系统攻城狮8 天前
Android tinyalsa深度解析之pcm_get_timestamp调用流程与实战(一百一十八)
android·pcm·tinyalsa·android hal·audio hal
奔跑吧 android9 天前
【车载Audio】【AudioHal 05】【高通音频架构】【audio_hw_device 核心接口解析】
音视频·qcom·aosp15·车载音频·audio hal·audio_hw_device
Android系统攻城狮10 天前
Android16进阶之MediaPlayer.getDuration调用流程与实战(二百二十九)
android16·音频进阶·音频性能实战
Android系统攻城狮10 天前
Android16进阶之MediaPlayer.isPlaying调用流程与实战(二百三十)
mediaplayer·android16·音频进阶·音频性能实战
Android系统攻城狮11 天前
Android tinyalsa深度解析之pcm_state调用流程与实战(一百一十七)
android·pcm·tinyalsa·音频进阶·音频性能实战
Android系统攻城狮11 天前
Android tinyalsa深度解析之pcm_get_available_min调用流程与实战(一百一十六)
android·pcm·tinyalsa·音频进阶·音频性能实战