You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose中使用MediaPlayer通过URL播放远程音频失败求助

解决MediaPlayer无法播放远程音频的问题

你的代码无法播放远程音频主要有三个核心问题:网络权限未声明、同步prepare阻塞主线程、MediaPlayer生命周期未正确管理,以下是具体修复方案:

1. 添加网络权限

在AndroidManifest.xml中添加INTERNET权限,否则App无法访问网络资源:

<uses-permission android:name="android.permission.INTERNET" />

注意:Android 9+默认禁止明文HTTP请求,但你的链接是HTTPS,无需额外配置android:usesCleartextTraffic="true"。

2. 使用异步prepare替代同步prepare

远程音频加载需要时间,直接调用prepare()会阻塞主线程,导致ANR或加载失败,应该用prepareAsync()并监听准备完成事件。

3. 正确管理MediaPlayer生命周期

避免每次点击都新建MediaPlayer,建议将MediaPlayer实例提升为可组合项的状态,同时在组件销毁时释放资源,防止内存泄漏。

修改后的完整代码

@Composable
fun MainScreen() {
    val context = LocalContext.current
    val url = "https://www.learningcontainer.com/wp-content/uploads/2020/02/Kalimba.mp3"
    // 用remember持有MediaPlayer实例,避免重复创建
    val mediaPlayer = remember { mutableStateOf<MediaPlayer?>(null) }

    // 在组件销毁时释放MediaPlayer资源
    DisposableEffect(Unit) {
        onDispose {
            mediaPlayer.value?.release()
            mediaPlayer.value = null
        }
    }

    Button(onClick = {
        mediaPlayer.value?.let { player ->
            // 如果已有实例,直接切换播放状态
            if (player.isPlaying) {
                player.pause()
            } else {
                player.start()
            }
            return@Button
        }

        // 新建MediaPlayer实例
        val player = MediaPlayer().apply {
            setAudioAttributes(
                AudioAttributes.Builder()
                    .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                    .setUsage(AudioAttributes.USAGE_MEDIA)
                    .build()
            )

            setOnPreparedListener { mp ->
                mp.start()
            }

            setOnErrorListener { _, what, extra ->
                Log.e("MediaPlayerError", "Error code: $what, extra: $extra")
                true
            }

            try {
                setDataSource(context, Uri.parse(url))
                prepareAsync() // 异步准备
            } catch (e: IOException) {
                Log.e("MediaPlayer", "Init failed", e)
                release()
            }
        }
        mediaPlayer.value = player
    }) {
        Text(
            text = if (mediaPlayer.value?.isPlaying == true) "Pause" else "Play"
        )
    }
}

额外说明

  • 错误监听:添加setOnErrorListener可以捕获具体错误原因,比如网络异常、音频格式不支持等,方便排查问题。
  • 状态切换:代码中增加了播放/暂停的切换逻辑,提升用户体验。
  • 资源释放:通过DisposableEffect在组件销毁时释放MediaPlayer,避免内存泄漏和系统资源浪费。

内容的提问来源于stack exchange,提问作者Daryl Wong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 23:20:45