Android MediaPlayer 如何通过URL实现播放后可离线收听音频功能
基于Android MediaPlayer实现断网可播放的在线音频方案
原生MediaPlayer默认仅对在线音频做最小必要的流式缓存,不会全量存储完整音频文件,直接传入远程URL无法满足断网后继续播放完整音频的需求,你需要搭配本地缓存代理的方案实现,具体步骤如下:
实现步骤
1. 初始化私有缓存目录
在应用私有缓存目录下创建专属的音频缓存文件夹,无需申请额外存储权限:
val audioCacheDir = File(context.cacheDir, "stream_audio_cache").apply { if (!exists()) mkdirs() }
2. 搭建本地HTTP代理服务做中转
这是实现边下边播、全量缓存的核心逻辑:
- 启动一个运行在本地的轻量HTTP代理服务,端口自行指定(建议用1024以上的非知名端口)
- 将原本传入MediaPlayer的远程音频URL,编码后拼接为本地代理地址,格式为
http://127.0.0.1:[代理端口]/?url=[编码后的远程URL] - 代理服务收到MediaPlayer的请求后,先检查本地是否有对应音频的完整缓存:
- 已存在完整缓存:直接读取本地缓存文件返回给MediaPlayer
- 无完整缓存:向远程服务器发起音频资源请求,下载到的数据一边写入本地缓存文件,一边同步返回给MediaPlayer播放,全量下载完成后标记该缓存为已完成状态
3. 配置MediaPlayer加载代理地址
直接将拼接好的本地代理地址作为数据源传给MediaPlayer即可,其他播放逻辑和常规在线播放一致:
val mediaPlayer = MediaPlayer().apply { setAudioAttributes( AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .setUsage(AudioAttributes.USAGE_MEDIA) .build() ) // 传入本地代理地址,而非直接传远程音频URL setDataSource(context, Uri.parse(localProxyUrl)) prepareAsync() setOnPreparedListener { // 缓冲到足够数据后自动播放 start() } }
4. 缓存清理逻辑(可选)
单音频体积可达50MB,建议配置缓存上限(比如设置总缓存上限为500MB),当缓存占用超出上限时按最近最少使用规则淘汰旧缓存,避免占用过多应用存储空间。
关键注意事项
- 不要采用先全量下载再播放的方案,会大幅增加用户等待时长,本地代理的边下边播方案可以做到和直接播放远程URL一致的启动速度
- 本地代理服务需要和应用生命周期绑定,应用退出时主动停止代理服务,避免资源泄漏
- 如果远程音频需要鉴权,请求头中的Cookie、Token等认证参数需要在代理发起远程请求时原样携带,避免鉴权失败
- 音频播放过程中如果出现断网,只要代理已经下载完完整的音频文件,后续播放会直接读取本地缓存,不会受到网络状态影响
内容的提问来源于stack exchange,提问作者Basterg
相关产品推荐
相关产品推荐

