Android播放网络流媒体音频需注意:使用AudioAttributes(弃用setAudioStreamType)、用prepareAsync避免主线程阻塞、Android9+需放行HTTP明文并声明网络权限。推荐优先HTTPS,配合Kotlin协程与lifecycleScope管理资源,防内存泄漏。
Android在线电台音频正确播放方法
时间:2026-07-15
浏览:228
文章目录
本文详解如何使用 MediaPlayer 正确播放 HTTP 流式音频(如 radio-browser.info 提供的电台链接),解决因缺少音频属性配置、线程阻塞或过时 API 导致的静音、崩溃或错误码(如 -2147483648、-38)问题。
在 Android 开发中,用 MediaPlayer 播放普通 MP3 文件并不困难,但一旦涉及实时流媒体音频——例如 Shoutcast 或 Icecast 电台流——问题就会变得复杂。许多开发者会遇到“无声音”“黑屏播放”或 Logcat 中显示大量错误码,如 MediaPlayer error (1, -2147483648) 和 error (-38, 0)。这些问题通常集中在几个关键点上:流媒体需要显式声明音频属性、不能在主线程阻塞、同时要适配 Android 9+ 的明文限制和 API 演进。
正确实现要点
首先,AudioAttributes 必须设置到位。setAudioStreamType() 从 API 26 起已弃用,正确做法是通过 AudioAttributes.Builder 明确指定用途(USAGE_MEDIA)和内容类型(CONTENT_TYPE_MUSIC),否则系统可能直接拒绝播放流媒体。
其次,prepare() 绝不能在主线程运行。setDataSource() 加 prepare() 是阻塞操作,放在主线程要么抛出 NetworkOnMainThreadException,要么直接 ANR。即使不崩溃,UI 卡顿也会严重影响体验。推荐使用 withContext(Dispatchers.IO) 或 prepareAsync() 加监听器来解决。
第三,明文网络请求需要放行。Android 9(API 28)开始默认禁止 HTTP 明文请求。如果电台地址是 http:// 开头,必须在 AndroidManifest.xml 中添加:
最后,不要忘记网络权限。在 AndroidManifest.xml 中声明:
推荐代码实现(Kotlin + Coroutines)
以下是一段可直接使用的代码:
private fun playAudio() { val audioAttributes = AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build() lifecycleScope.launch { try { val mediaPlayer = MediaPlayer().apply { setAudioAttributes(audioAttributes) setDataSource("https://play.sas-media.ru/play_256") // 建议优先使用 HTTPS setOnPreparedListener { it.start() Toast.makeText(this@MainActivity, "Radio is playing", Toast.LENGTH_SHORT).show() } setOnErrorListener { _, what, extra -> Log.e("MediaPlayer", "Error: $what, Extra: $extra") Toast.makeText(this@MainActivity, "Playback failed", Toast.LENGTH_LONG).show() return@launch } prepareAsync() // 非阻塞,回调驱动 } } catch (e: IOException) { Log.e("MediaPlayer", "DataSource setup failed", e) Toast.makeText(this@MainActivity, "Failed to load stream", Toast.LENGTH_LONG).show() } } }
关键说明:
- 使用 prepareAsync() + setOnPreparedListener 是更安全、响应式的模式,避免手动管理线程;
- lifecycleScope 替代 GlobalScope,确保 Activity 销毁时协程自动取消,防止内存泄漏;
- setOnErrorListener 可捕获具体错误码(如 what=1 表示 MEDIA_ERROR_UNKNOWN,常因网络、格式或权限问题),便于精准调试。
注意事项与常见问题排查
优先使用 HTTPS 流地址。这能避免明文流量配置,兼容性和安全性更好。总之,能使用 HTTPS 就不要使用 HTTP。
流协议兼容性需要留意。MediaPlayer 对 HTTP Live Streaming (HLS) 和部分 Icecast/Shoutcast 流原生支持,但遇到某些编码(如 AAC+)或复杂的重定向链路,可能无法正常工作。如果持续失败,可以尝试 ExoPlayer——Google 官方推荐,对流媒体支持更稳定。
资源释放不能忽略。实际项目中,务必在 onDestroy() 或暂停时调用 mediaPlayer.release(),防止资源泄露。
后台播放是另一个话题。如果需要锁屏后继续播放,需要结合 Foreground Service 和 AudioManager 音频焦点管理来实现,这属于进阶需求,不在本文讨论范围内。
掌握以上配置,基本上就能稳定播放 radio-browser.info 等平台提供的绝大多数网络电台流。记住:流媒体不是文件,配置和线程管理才是关键。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。